当与下划线一起使用时,部分函数应用程序会过早地运行代码块

时间:2011-02-07 05:40:43

标签: scala currying partialfunction eta-expansion

假设:

def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") } 

我可以用:

来调用它
save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown

以下是部分申请的奇怪行为:

save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown

立即评估代码块而不作为函数传递。上述两个陈述有什么区别?

2 个答案:

答案 0 :(得分:3)

第一种情况

save(throw new RuntimeException("boom!")) _ 

根据"Scala Reference"(§6.7),使用尾随下划线代替参数列表,并将表达式转换为

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))

立即评估def save的第一个参数。

  

如果e,表达式e _是格式良好的   是方法类型或e是a   按名称调用参数。如果e是a   带参数的方法,e _表示   e由eta转换为函数类型   扩张(§6.26.5)。如果e是a   无参数方法或按名称调用   type =&gt; T的参数,e _表示   type()=&gt;的功能T,哪个   评估e何时应用于   空参数列表()。

为了使事情按预期运作,需要进行一些修改:

scala> def save(f:() => Any)(run:Boolean) { if (run) { println("running f"); f() } else println("not running f") }
save: (f: () => Any)(run: Boolean)Unit

scala> val f = save(() => throw new RuntimeException("boom!")) _
f: (Boolean) => Unit = <function1>

scala> f(true)
running f
java.lang.RuntimeException: boom!
        at $anonfun$1.apply(<console>:6)

第二种情况

save(throw new RuntimeException("boom!"))(_)

根据"Scala Reference"(§6.23),当占位符用作参数的替代时,表达式将转换为

val f: (Boolean) => Unit = save(throw new RuntimeException("boom!"))(_)

答案 1 :(得分:0)

目前正在审核eta扩展下按名称调用参数的行为,请参阅this bug。您的代码按预期工作(即,行save(throw new RuntimeException("boom!")) _返回函数而不抛出异常),最近的每晚构建版本为2.10。让我们看看它是否会一直持续到发布!

另见this question关于eta扩展的一般情况的相关问题,不涉及名称。