使用 curried 函数和映射的评估顺序

Order of evaluation with curried function and map

我对柯里化函数何时被替换以及这对程序性能的影响有一些疑问。

具体来说,给出以下代码:

def curriedFun(f: Stuff => OtherStuff)(stuff: Stuff) = ...

def normalFun(stuff: Stuff): OtherStuff = ...

...

listOfListsOfStuff: List[Stuff] = ...

val otherStuff: List[OtherStuff] =
      listOfListsOfStuff.map(curriedFun(normalFun))

我的疑问是块的最后一次调用,更具体地说 map 如何与 curried 函数交互。特别是:

val substitutedFun = curriedFun(normalFun)
val otherStuff: List[OtherStuff] =
      listOfListsOfStuff.map(substitutedFun)

我的直觉告诉我应该相当于事先代入函数(第一个选项),但我实在无法理解为什么,也不知道在哪里看...

方法的参数在调用方法之前计算(除非参数是按名称)。所以 map 的参数是在调用 map 之前计算的。

所以在这种情况下,curriedFun(normalFun)被计算一次给一个函数,然后这个函数被传递给mapmap 然后将此函数应用于 listOfListsOfStuff 的每个元素。 map 的参数是由柯里化函数生成的这一事实与执行顺序无关。

就我个人而言,我发现 scala -print 通常对这类问题很有用。例如,创建以下 Main.scala 文件

// Main.scala
def foo(i: Int)(j: String): String = j
List("hello", "world").map(foo(42))

然后执行 scala -print Main.scala 输出类似

def foo(i: Int, j: String): String = j;
def $anonfun$new(j: String): String = anon.this.foo(42, j);
new collection.immutable.::("hello", new collection.immutable.::("world", scala.collection.immutable.Nil)).$asInstanceOf[List]().map({
   ((j: String) => anon.this.$anonfun$new(j))
});

map 执行之前,我们看到柯里化被解析为 $anonfun$new 函数一次。