当隐式派生所需类型时,Scala 不应用隐式转换

Scala does not apply implicit conversion when required type is derived implicitely

我可能遇到过链式隐式转换问题 (http://docs.scala-lang.org/tutorials/FAQ/chaining-implicits.html)。而且我不知道如何解决它。

我在下面附上了一个 SSCCE 示例来说明问题。让我在这里添加一些细节:

1) 我想要一个像下面这样的方法:

def chainedTransform[A, B, C](a: A)(f1: F[A, B], f2: F[B, C]): C

它应该将值从类型 A 转换为类型 C

2) 可能会发生具有必要类型参数的转换器 F 不在范围内,但令人满意的隐式转换是。

3) 下面的代码片段演示了整个方法。

  test("Mutliple conversions") {
    val f1: Function1[String, Int] = (s) => s.toInt
    val f2: Function1[Int, Boolean] = (i) => i > 0
    val f3: Function[Option[Int], Option[Boolean]] = (iOpt) => iOpt map (_ > 0)

    implicit def toOptFun[A, B](f: Function1[A, B]): Function1[Option[A], Option[B]] =
      new Function1[Option[A], Option[B]] {
        override def apply(v1: Option[A]): Option[B] = v1 map f
      }

    case class Test[A](param: A) {
      def transform[B](t1: Function1[A, B]): B = t1(param)
      def chainedTransform[B, C](t1: Function1[A, B], t2: Function1[B, C]): C = t2(t1(param))
    }

    val test1 = Test("123")
    assert(test1.chainedTransform(f1, f2))

    val test2 = Test(Option("123"))
    //toOptFun implicit conversion is applied successfully
    assert(test2.transform(f1) == Some(123))

    //Does not compile: 
    //test2.chainedTransform(f1, f2)
    //  [error]  found   : Int => Boolean
    //  [error]  required: Option[Int] => Boolean
    //  [error]     test2.chainedTransform(f1, f2)
    //  [error]                                ^

    //f3 is exactly what toOptFun(f2) would produce if applied
    assert(test2.chainedTransform(f1, f3) == Some(true))
  }

有什么让它发挥作用的想法吗?

这仅仅是因为 Scala 试图为 test2.chainedTransform(f1, f2) 选择错误的类型。正如错误消息所暗示的那样,编译器正在寻找一个 Option[Int] => Boolean 而你所拥有的只是对 Option[Int] => Option[Boolean].

的隐式转换

如果你用类型注释向编译器提示你真正想要什么,一切都会编译。

test2.chainedTransform(f1, f2): Option[Boolean]

作为旁注,chainedTransform 是函数的特定情况下的反向函数组合(函数的 andThen 方法),更普遍的是箭头的反向组合(the >>> operator for the Arrow typeclass in Scalaz ).