Curried function in scala

[亡魂溺海] 提交于 2021-02-07 07:12:17

问题


I have a definition of next methods:

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

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

the second one is curried version of first one. Then if I want to partially apply second function I have to write val res2 = add2(2) _. Everything is fine. Next I want add1 function to be curried. I write

val curriedAdd = (add1 _).curried

Am I right that curriedAdd is similiar to add2? But when I try to partially apply curriedAdd in a such way val resCurried = curriedAdd(4) _ I get a compilation error. Then I fix it to

val resCurried = curriedAdd(4)

Why the result of a Functions.curried differs from curried version of add function(from add2)?


回答1:


Firstly curriedAdd is same as add2 _ and not add2. add2 is just a method.

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

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

About the second question. I think the below is the reason. Doing

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) _ does not work. Lets look at scala manual (§6.7)-

The expression e _ is well-formed if e is of method type or if e is a call-by-name parameter. If e is a method with parameters, e _ represents e converted to a function type by eta expansion (§6.26.5). If e is a parameterless method or call-by-name parameter of type =>T , e _ represents the function of type () => T , which evaluates e when it is applied to the empty parameterlist ().

Remember it only evaluates if it is a method or call-by-name parameter. In curriedAdd(23) _, it does not evaluate curriedAdd(23) but checks if it is a method or call-by-name. It is not a method nor a call-by-name parameter.

It is not by-name because by-name is the property of variable. Above you get a by-name parameter after evaluating curriedAdd(23) but curriedAdd(23) in itself is not a by-name variable. Hence the error (Ideally the compiler should have coverted it). Note that the below works:

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

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

The above works because res80 _, here you are applying _ to a call-by-name parameter and hence does the conversion.




回答2:


To answer this question, let's take a look at the REPL.

First we define the two functions as you did.

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

We have defined two functions. The first one expects two parameters in one parameterlist. The second one expects two parameters, each one in an own parameterlist. The result type is the same.
Let's move on.

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

You just created a partial applied function, that expects one parameter and returns a partial applied function of type Int => Int. This is not as similar to add2 as you expect it to be.
To achieve the same for add2, you would need to call

scala> val curriedAdd2 = add2 _
curriedAdd2: Int => (Int => Int) = <function1>


来源:https://stackoverflow.com/questions/18398574/curried-function-in-scala

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!