使用高阶函数映射

Luo*_*inh 1 scala

这些陈述有什么区别?

val numbers = List(1, 2, 3, 4)
numbers map println
// vs.
numbers map (x => println(x))
Run Code Online (Sandbox Code Playgroud)

Scala如何知道println会反复处理每个数字

谢谢.

Jör*_*tag 5

这些陈述有什么区别?

val numbers = List(1, 2, 3, 4)
numbers map println
// vs.
numbers map (x => println(x))
Run Code Online (Sandbox Code Playgroud)

map将变换单个元素的函数作为其参数.map然后将此函数应用于每个元素,并返回包含已转换元素的集合.(BTW,这就是为什么这段代码没有意义:a)map忽略返回值,并且b)println总是返回Unit,所以你最终会得到一个Units 列表.foreach将是在这里使用的正确方法.)

在第二个示例中,您将λ(一个匿名的第一类函数对象)传递给map.

在第一个例子中,你究竟传递给了map什么?看起来你正在传递一个方法,但这不可能是:a)map接受一个函数,而不是一个方法,而b)方法不是对象,所以你根本无法传递它们.您必须以某种方式将方法转换和/或包装到函数中.

在第二个示例中,您将非常明确地执行此操作:您有一个调用该方法的函数.第一个例子更隐含.Scala有一个名为η-expansion的功能,它允许你"提升"一个方法来运行,这将部分地将该方法应用于其隐式this参数,但保持其他(常规)参数不受约束.

的语法,这是无处不在下划线:foo.bar _是指"取方法barfoo,结合其thisfoo并将其转换成一个函数".在这种特殊情况下,您println将其绑定this到顶级REPL上下文对象(这并不重要,因为println它实际上并不关心它this,它像程序一样使用)并将其转换为函数.

但等等,没有下划线?那就对了.在情况下,Scala编译器能确定你实际上并不想调用的方法,但它包装成一个功能(即当你不传递一个参数列表,该方法需要一个参数列表,以及上下文期望一个类型这与方法的类型兼容),然后Scala将为您执行隐式η-扩展.

那么,让我们回到你的问题:

这些陈述有什么区别?

好了,一方面,这些差异是什么上述I:第一个例子使用隐式η膨胀,第二示例使用显式λ.OTOH,没有区别:它们都是从println方法中创建一个函数,第二个只是以更复杂的方式来创建它.

Scala如何知道println会反复处理每个数字

它没有.a)不是println"照顾每一个数字",它是map这样做的,而且b)Scala什么都不知道,那map就是写的.

非常简单,map看起来像这样:

sealed trait MyList[+T] {
  def map[U](function: T ? U): MyList[U]
  def foreach(procedure: T ? Unit)
}

case object EmptyList extends MyList[Nothing] {
  // mapping the empty list returns the empty list
  def map[U](function: Nothing ? U) = EmptyList

  def foreach(procedure: Nothing ? Unit) = ()
}

final case class ListCell[+T](first: T, rest: MyList[T]) extends MyList[T] {
  // mapping a non-empty list returns the result of transforming the first 
  // element of the list and recursively mapping the rest of the list
  def map[U](function: T ? U) = ListCell(function(first), rest map function)

  def foreach(procedure: T ? Unit) = { procedure(first); rest foreach procedure }
}
Run Code Online (Sandbox Code Playgroud)

以下是我们如何使用简单的小清单:

val list: MyList[Short] = ListCell(1, ListCell(2, ListCell(3, EmptyList)))

list map (1+)
// => ListCell(2, ListCell(3, ListCell(4, EmptyList)))

list map(_.toString)
// => ListCell(1, ListCell(2, ListCell(3, EmptyList)))

list map println
// 1
// 2
// 3
// => ListCell((), ListCell((), ListCell((), EmptyList)))
// here you can see the useless list of Units that is returned

list foreach println
// 1
// 2
// 3
// foreach just returns nothing
Run Code Online (Sandbox Code Playgroud)