我对下一个方法有一个定义:
def add1(x: Int, y: Int) = x + y
def add2(x: Int)(y: Int) = x + y
第二个是第一个的curried版本。然后,如果我想部分应用第二个函数,我必须写val res2 = add2(2) _
。一切都好。接下来我希望add1
函数被curry。我写了
val curriedAdd = (add1 _).curried
我是对的,curriedAdd与add2
类似吗?
但是,当我尝试以这种方式curriedAdd
部分应用val resCurried = curriedAdd(4) _
时,我收到编译错误。然后我把它固定到
val resCurried = curriedAdd(4)
为什么Functions.curried
的结果与添加函数的curried版本(来自add2
)不同?
答案 0 :(得分: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是a,则表达式e _是格式良好的 按名称调用参数。如果e是带参数的方法,e _ 表示e通过eta扩展转换为函数类型(第6.26.5节)。 如果e是无参数方法或类型=&gt; T的名称调用参数, e _表示type()=&gt;的函数。 T,评估e时 它应用于空参数列表()。
请记住,它仅评估它是方法还是按名称调用参数。在curriedAdd(23) _
中,它不会评估curriedAdd(23),而是检查它是方法还是按名称调用。它不是方法,也不是按名称调用参数。
它不是按名称,因为 by-name 是变量的属性。在评估curriedAdd(23)
之后,您将获得按名称参数,但curriedAdd(23)
本身不是按名称变量。因此错误(理想情况下编译器应该转换它)。请注意,以下内容有效:
scala> curriedAdd(23)
res80: Int => Int = <function1>
scala> res80 _
res81: () => Int => Int = <function0>
上述工作原因是res80 _
,您在此处将_
应用于按名称调用参数,从而进行转换。
答案 1 :(得分: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>