2014-06-06 155 views
2

我碰到一些代码排在斯卡拉类似的形式是这样的:斯卡拉语法帮助柯里

def test1(f : Int => Int)(x : Int) = x + f(x) 

    def test2(f : Int => Int)(x : Int) = f(x) 

    test2(test1(x => 2*x))(2) 

我很困惑,所以功能测试1需要一个功能和诠释作为参数,并返回一个函数,对?那么如何test1(x => 2*x)有效,并返回一个函数test2?显然它需要2个整数参数,但为什么? test2(test1(x => 2*x))(2)声明如何展开?

在此先感谢。

回答

0

此:

test2(test1(x => 2*x))(2) 

扩展到这一点:

test2(y => test1(x => 2*x)(y))(2) 

Scala的多参数列表的方法可以起到像很多其他语言咖喱功能,但实际上作为方法来实现,需要它们的所有参数,并且这在句法中显示。例如,如果你把这个放入REPL:

test1(x => 2*x) 

它会抱怨缺少参数。这种语法允许的是“eta-expansion”,其中一个方法被转换成一个函数。如果你写:

val func: Int => Int = test1(x => 2*x) _ 

你可以得到一个代表部分应用test1的功能。如果上下文需要它,Scala会自动执行eta-expansion,这是test2(test1(x => 2*x))(2)发生的情况。请注意,test1本身永远不会返回函数,但编译器将根据需要构建一个函数。

但是,如果你定义test1喜欢:

def test1(f : Int => Int) = (x : Int) => x + f(x) 

编译器会接受test1(x => 2*x)没有_。此外,在底层实现中,将只有一个类实现闭包,但由于原始定义,每个部分应用test1都会导致为其创建新类。另一方面,给定两个参数时效率较低,因为总是创建闭包。

+0

好的,我可以这样说,在这种情况下,Scala使用eta-expansion来实现函数currying,但它鼓励我们认为test1返回一个函数? – ekinrf

+0

类别。有很多文档指出多个参数列表实现了currying,但是您不能仅仅通过真正的卷曲就可以盲目地使用它,并且大多数具有多个参数列表的方法实例并不打算部分应用,例如, 'list.foldLeft(0)'很少见。看看我的新编辑 - 我展示了如何创建一个真正的咖喱方法/函数。 – wingedsubmariner

1

函数test1接受函数和Int作为参数,并返回一个函数,对吗?

不,它只接受一个函数作为它的参数并返回一个函数。返回的函数接着将int作为参数并返回一个int。

那么test1(x => 2 * x)如何才能有效并返回函数test2?

我希望现在清楚。

声明test2(test1(x => 2 * x))(2)如何展开?

test1x => 2*x作为参数被调用并返回一个函数。然后test2以该返回的函数作为参数被调用并返回另一个函数。然后用2作为它的参数调用另一个函数。

+0

谢谢!我非常喜欢编程风格,认为currying只是一个语法糖。这现在很有意义。 – ekinrf

+0

这是不正确的。在REPL中自己尝试'test1(x => 2 * x)'。 – wingedsubmariner