斯卡拉隐含的提升

时间:2012-07-11 21:07:00

标签: scala implicits

我想隐式地将函数从A => B转换为List[A] => List[B]

我写了以下隐含的定义:

implicit def lift[A, B](f: A => B): List[A] => List[B] = ...

不幸的是,当我编写以下代码时,不会应用隐式:

val plusOne: (List[Int]) => List[Int] = (x: Int) => (x + 1)

如果我用显式时间注释该函数,它可以正常工作。

为什么呢?我该如何解决?

更新。似乎问题是匿名函数特有的。比较:

@Test
def localLiftingGenerics {
  implicit def anyPairToList[X, Y](x: (X, Y)): List[X] => List[Y] = throw new UnsupportedOperationException  

  val v: List[String] => List[Int] = ("abc", 239)
}

@Test
def localLiftingFuns {
  implicit def fun2ListFun[X, Y](f: X => Y): List[X] => List[Y] = throw new UnsupportedOperationException

  val v: List[String] => List[Int] = ((x: String) => x.length)
}

第一个编译得很好。第二个标记为错误

4 个答案:

答案 0 :(得分:6)

根据The Scala Language Specification /表达式/匿名函数(6.23):

  

如果匿名函数的预期类型是表单   scala.Function n [ S 1 ,...,S n ,R ], e 是 R ...

因此,函数的结果类型将被推断为List[Int],除非您将函数定义与函数值赋值分开(以消除期望的类型):

val function = (x: Int) => (x + 1)
val plusOne: (List[Int]) => List[Int] = function

或明确指定函数类型:

val plusOne: (List[Int]) => List[Int] = ((x: Int) => (x + 1)): Int => Int

答案 1 :(得分:1)

(Scala 2.9.1-1(Java HotSpot(TM)64位服务器VM,Java 1.7.0_05)

第一次观察:如果您复制fun2ListFun并将其重命名为,例如``fun2ListFun,那么您将获得

found   : String => <error>
 required: List[String] => List[Int]

Note that implicit conversions are not applicable because they are ambiguous:
 both method fun2ListFun2 of type [X, Y](f: X => Y)List[X] => List[Y]
 and method fun2ListFun of type [X, Y](f: X => Y)List[X] => List[Y]
 are possible conversion functions from String => <error> to List[String] => List[Int]
  val v: List[String] => List[Int] = ((x: String) => x.length)

看起来好像编译器认为这两种含义都是适用的。


第二个观察结果:

分裂

val v: List[String] => List[Int] = ((x: String) => x.length) /* Error*/

val f = ((x: String) => x.length)
val v: List[String] => List[Int] = f /* Works */

让编译器开心。

答案 2 :(得分:1)

输入值的隐式转换编译。所以我们只对匿名函数

的输出有问题
 def localLiftingFuns {
   implicit def fun2ListFun[X, Y](f: X => Y): List[X] => Y = throw new UnsupportedOperationException

   val v: List[String] => Int = ((x: String) => x.length)
 }

使用第二次隐式转换的可能修复:

 def localLiftingFuns {
   implicit def fun2ListFun[X, Y](f: X => List[Y]): List[X] => List[Y] = throw new UnsupportedOperationException
   implicit def type2ListType[X](x:X): List[X] = throw new UnsupportedOperationException

   val v: List[String] => List[Int] = ((x: String) => x.length)
 }

此版本编译。

答案 3 :(得分:0)

似乎编译器很难确定函数类型的变化。如果你能给他一点帮助,那就行了:

scala> implicit def lift[A,B](f: A => B) = (_:List[A]).map(f)
lift: [A, B](f: (A) => B)(List[A]) => List[B]

scala> val f: List[Int] => List[Int] = ((_:Int) + 1):(Int => Int)
f: (List[Int]) => List[Int] = <function1>
相关问题