6

我有下一个方法的定义:

def add1(x: Int, y: Int) = x + y

def add2(x: Int)(y: Int) = x + y

第二个是第一个的咖喱版本。然后,如果我想部分应用第二个函数,我必须编写val res2 = add2(2) _. 一切都很好。接下来我想要add1函数被咖喱。我写的

val curriedAdd = (add1 _).curried

我对 curriedAdd 相似add2吗?但是当我尝试以curriedAdd这种方式部分应用时,val resCurried = curriedAdd(4) _我得到一个编译错误。然后我将其修复为

val resCurried = curriedAdd(4)

为什么 a 的结果Functions.curried与 add 函数的 curried 版本不同(from add2)?

4

2 回答 2

4

首先curriedAdd是相同的add2 _和不是add2。add2 只是一种方法。

scala> curriedAdd
res52: Int => (Int => Int) = <function1>

scala> add2 _
res53: Int => (Int => Int) = <function1>

关于第二个问题。我认为原因如下。正在做

scala> val i = curriedAdd(23)
i: Int => Int = <function1>

scala> i _
res54: () => Int => Int = <function0>

scala> curriedAdd(23) _
<console>:10: error: _ must follow method; cannot follow Int => Int
              curriedAdd(23) _

curriedAdd(23) _不起作用。让我们看一下 scala 手册(§6.7)-

如果 e 是方法类型或 e 是按名称调用的参数,则表达式 e _ 是格式良好的。如果 e 是带参数的方法,则 e _ 表示 e 通过 eta 扩展(第 6.26.5 节)转换为函数类型。如果 e 是 =>T 类型的无参数方法或按名称调用参数,则 e _ 表示 () => T 类型的函数,它在应用于空参数列表 () 时计算 e。

请记住,它仅评估它是方法还是按名称调用的参数。在 curriedAdd(23) _中,它不评估 curriedAdd(23) 而是检查它是方法还是名称调用。它不是方法,也不是名称调用参数。

它不是按名称,因为按名称是变量的属性。在上面,您在评估后得到一个按名称curriedAdd(23)参数,但curriedAdd(23)它本身不是按名称变量。因此错误(理想情况下编译器应该已经隐藏它)。请注意,以下工作:

scala> curriedAdd(23)
res80: Int => Int = <function1>

scala> res80 _
res81: () => Int => Int = <function0>

上面的工作是因为res80 _,在这里您正在应用_一个按名称调用的参数,因此进行了转换。

于 2013-08-23T10:44:45.183 回答
0

要回答这个问题,让我们看一下 REPL。

首先,我们像您一样定义这两个函数。

scala> def add1(x: Int, y: Int) = x + y
add1: (x: Int, y: Int)Int

scala> def add2(x: Int)(y: Int) = x + y
add2: (x: Int)(y: Int)Int

我们定义了两个函数。第一个期望在一个参数列表中有两个参数。第二个需要两个参数,每个参数都在自己的参数列表中。结果类型相同。
让我们继续。

scala> val curriedAdd = (add1 _).curried
curriedAdd: Int => (Int => Int) = <function1>

您刚刚创建了一个部分应用函数,它需要一个参数并返回一个类型为 的部分应用函数Int => Int。这并不像add2您期望的那样相似。
为了达到同样的效果add2,您需要调用

scala> val curriedAdd2 = add2 _
curriedAdd2: Int => (Int => Int) = <function1>
于 2013-08-23T09:51:40.977 回答