堆叠隐式转换

Stacking implicits conversions

我正在尝试尽可能轻量级地使用期货。

这是我当前的测试代码:

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
   */
}

extracted 和 extracted2 都在工作,但每个都只使用我定义的两个隐式转换之一。

extracted3 是我的目标,隐含地将 plus 和 cst1 提升为 Future[X] 值并将 a <*> b 转换为 ap(a,b)。但是编译器好像不同意我的看法

我想要实现的目标可行吗?如果是这样,我必须更改什么才能使其正常工作?

PS :我的灵感来自于我使用 haskell.

所见

我认为您违反了 "one at a time" 规则。

来自 Programming in Scala,(第 1 版):

One-at-a-time Rule: Only one implicit is tried. The compiler will never rewrite x + y to convert1(convert2(x)) + y. Doing so would cause compile times to increase dramatically on erroneous code, and it would increase the difference between what the programmer writes and what the program actually does. For sanity's sake, the compiler does not insert further implicit conversions when it is already in the middle of trying another implicit.


正如@tkachuko 所指出的,可能有一种使用隐式参数来解决此限制的方法,但一个简单的解决方案是将 FutureInfix 分成两部分。

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)
}