带有咖喱函数的评估顺序和地图

时间:2019-08-06 13:29:41

标签: scala currying

我对何时替换咖喱函数及其对程序性能的影响有疑问。

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

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)
  • 还是用otherStuff列表中的每个元素替换一次?

我的直觉告诉我应该等同于预先替换功能(第一个选项),但是我真的不明白为什么,而且我也不知道在哪里看...

2 个答案:

答案 0 :(得分:3)

方法的参数是在调用该方法之前计算的(除非参数是按名称)。因此,map的参数是在调用map之前计算出来的。

因此,在这种情况下,curriedFun(normalFun)被计算一次以提供一个函数,然后将该函数传递给mapmap然后将此功能应用于listOfListsOfStuff的每个元素。 map的参数由咖喱函数生成的事实与执行顺序无关。

答案 1 :(得分:2)

我个人认为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$1(j: String): String = anon$1.this.foo(42, j);
new collection.immutable.::("hello", new collection.immutable.::("world", scala.collection.immutable.Nil)).$asInstanceOf[List]().map({
   ((j: String) => anon$1.this.$anonfun$new$1(j))
});

在执行$anonfun$new$1之前,我们看到的curry被解析为map函数一次。