scala中的curried函数

时间:2013-08-23 08:45:59

标签: scala currying

我对下一个方法有一个定义:

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)不同?

2 个答案:

答案 0 :(得分:4)

首先curriedAddadd2 _相同,而不是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>