通过' =>'和(其次)通过1个arg列表然后是另一个返回scala函数的curriable函数

时间:2015-04-20 23:47:17

标签: scala lambda functional-programming currying

我开始学习一点Scala,我基本上都是 理解返回函数和currying的函数,但是 我已经看到了这样做的两种语法,我想要更好 了解差异,也许还有一些理论背后的原因 发生了什么事。

在第一种方法中(使用=>)我可以通过指定来理解函数 要绑定到变量x的参数。但是,当我尝试这样做 使用第二种方法,编译器告诉我需要指定_ 第二个参数的外卡。

我明白我需要做什么,但我不知道为什么我需要做 这样的事情。有人可以告诉我Scala编译器是什么 在这做什么?

使用=>

的第一种方法
def add(x:Int) = (y:Int) => x + (-y)
add: (x: Int)Int => Int

scala> def adder = add(100)   // x is bound to 100 in the returned closure
adder: Int => Int

scala> adder(1)
res42: Int = 99

使用一个arg列表后跟另一个

的第二个方法
scala> def add2(x:Int)(y:Int) :  Int =  x + y
add2: (x: Int)(y: Int)Int

scala> def  adder2 = add2(100)
<console>:9: error: missing arguments for method add2;
follow this method with `_' if you want to treat it 
 as a partially applied function

       def  adder2 = add2(100)
                         ^

scala> def  adder2 = add2(100) _    // Okay, here is the '_'
adder2: Int => Int

scala> adder2(1)                    // Now i can call the curried function
res43: Int = 101

1 个答案:

答案 0 :(得分:4)

您所看到的是方法类型功能类型之间的区别。这是一个微妙的,有时令人困惑的差异。 This answer包含对方法类型和函数类型之间差异的非常全面的解释。这是您的问题的一些最相关的点:

  

函数类型(大致)是(T1, ..., Tn) => U形式的一种类型,它是标准库中特征FunctionN的简写。

     

方法类型是非值类型。这意味着没有值 - 没有对象,没有实例 - 使用方法类型......方法类型是def声明 - 除了def之外的所有内容。

您无法直接指定方法执行val

def foo(x: Int) = x
val myFooVal = foo //does not compile   

eta-expansion 的过程可以将方法转换为函数,您可以将其分配给val

val myFooVal = foo _

Here是一篇博客文章,深入探讨了eta扩展。

您的示例中有趣的是您将方法与函数混合。这完全没问题,但它可能是你在这里迷惑的一部分:

def add(x:Int) = (y:Int) => x + (-y)

这是返回函数的方法,而这个:

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

是一个纯方法,与所有方法一样,可以使用eta-expansion将其转换为函数类型:

add2 _ //Int => (Int => Int)
add2(2) _ //Int => Int

在REPL中玩游戏可能会有所启发,看看Scala如何区别对待这些类型:

def add(x:Int) = (y:Int) => x + (-y)
//add: (x: Int)Int => Int

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

注意REPL的打印输出在这里有何不同。在第一个示例中,我们可以看到add是一个返回Int => Int类型的方法,这是一个函数。在第二个示例中,方法语法通过第二个参数保留。