2016-10-26 2 views
0

J'essaie de rendre mon utilisation des contrats à terme aussi légère que possible.L'empilement implique des conversions

Voici mon code de test en cours:

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 
import scala.util.Failure 
import scala.util.Success 

object Test1 extends App { 

    def lift[A](a: A): Future[A] = Future { a } 

    def ap[A, B](fct: Future[A => B], param: Future[A]): Future[B] = 
    for { 
     c <- param 
     o <- fct 
    } yield (o(c)) 

    implicit def valToFuture[A](elem: A): Future[A] = lift(elem) 
    implicit class FutureInfix[A, B](val x: Future[A => B]) extends AnyVal { 
    def <*>(that: Future[A]) = ap(this.x, that) 
    } 

    val plus1: Int => Int = (x: Int) => x + 1 
    val cst1: Int = 1 

    val extracted: Future[Int] = ap(plus1, cst1) 
    val extracted2: Future[Int] = lift(plus1) <*> lift(cst1) 
    val extracted3: Future[Int] = plus1 <*> cst 
    /* 
    * - value <*> is not a member of Int ⇒ Int 
    * - not found: value cst 
    */ 
} 

extrait et extracted2 travaillent mais sont chacun en utilisant seulement l'un des deux conversion implicite que j'ai défini.

extrait3 est ce que je vise, en soulevant implicitement plus et cst1 aux valeurs futures [X] et en convertissant a <*> b en ap(a,b). Mais le compilateur ne semble pas être d'accord avec moi.

Est ce que j'essaye de réaliser possible? Si oui, que dois-je changer pour que ça marche? PS: Ce genre d'inspiré de ce que j'ai vu en utilisant haskell.

+0

'cst' est supposé être indéfini? – tkachuko

+0

non, vous ne pouvez pas enchaîner 2 conversions implicites en même temps. – flavian

Répondre

3

Je pense que vous vous heurtez à la règle "un à la fois".

De Programming in Scala, (1ère édition):

un-à-un-temps Règle: Un seul est jugé implicite. Le compilateur ne réécrira jamais x + y pour convertir 1 (convert2 (x)) + y. Cela provoquerait une augmentation considérable du temps de compilation sur le code erroné, et cela augmenterait la différence entre ce que le programmeur écrit et ce que le programme fait réellement. Pour des raisons de santé mentale, le compilateur n'insère pas d'autres conversions implicites lorsqu'il est déjà au milieu pour essayer une autre implicite.


Comme @tkachuko a souligné, il y a probablement un travail autour de cette limitation en utilisant des paramètres implicites, mais une solution simple est de diviser FutureInfix en deux parties.

implicit class FromFutureInfix[A, B](x: Future[A => B]) { 
    def <*>(that: Future[A]) = ap(x, that) 
} 
implicit class ToFutureInfix[A, B](x: A => B) { 
    def <*>(that: A) = ap(x, that) 
} 
+0

Mais on dirait que la cible peut être atteinte avec un chaînage implicite: http://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html – tkachuko