Scala - 在地图函数中与lambda混淆

时间:2016-07-27 14:03:24

标签: scala lambda

我正在学习Scala并正在尝试使用命令行。我无法理解为什么第二行无法编译。有人可以解释一下。

val list = List(1,2,3,4)
list.map(_+1)           //This works. List(2,3,4,5)
list.map(List(_+1))     //But, Compilation Fails here
list.map(x=>List(x+1))  //This works. List(List(2),List(3),List(4),List(5))

谢谢。

2 个答案:

答案 0 :(得分:6)

Scala会将_(在占位符位置使用时)扩展为x => x,除非此类扩展会导致身份函数(在此答案结尾处更多内容):

list.map(_+1)       // same as list.map(x => x + 1)       (1)
list.map(List(_+1)) // same as list.map(List(x => x+1))   (2)

对于(1),scala可以推断x的类型为Int(自list: List[Int]起)。
(2)失败,

error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))

因为scala无法在x中推断出List(x => x+1)的类型。

关于扩展和身份功能:

scala> list.map(List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3), List(4))

有效,因为list.map(List(x => x))扩展被拒绝了,下一个可能的扩展名是list.map(x => List(x)),这会产生res3

答案 1 :(得分:1)

list的类型为List[Int]。因此,list.map(...)的参数必须是从Int到某个函数的函数。

你试图用List(_+1)创建的是一个从整数到整数的函数列表,这些函数碰巧有一个元素:后继函数。

无法编译,因为这是Scala编译器无法推断表达式类型的情况之一。但实际上,List[_] 是从Int

的有效函数

val f = List(99, 88, 77)
f(1)                     // -> 88

因此,要编译代码,必须给编译器一些提示,以便进行类型检查:

val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]](_ + 1))
//           ^^^^^^^^^^^^^^^^^^^^ type annotation

这也是有效的:

list.map(List[Int => Int]](_ + 1))

它将编译,但它会在运行时失败,因为您正在尝试获取单元素列表的元素1,2,3和4。如果列表仅包含零(该特定列表的唯一有效索引),则它可以工作:

val list = List(0, 0, 0)
list.map(List[Function[Int, Int]](_ + 1))
// -> evaluates to a list of three functions 

...或者如果函数列表包含足够的索引1,2,3和4元素:

val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]]( // a list of 5 functions:
  _ + 1,                           // 0) the successor function,
  _ * 10,                          // 1) the "append a zero" function,
  Math.abs,                        // 2) the absolute value function,
  _ / 2,                           // 3) the half function
  x => 2                           // 4) the constant function with value 2
))
// -> evaluates to a list of four functions. Can you guess which ones?