Scala - tupled和部分应用函数

时间:2015-04-10 09:39:18

标签: scala

我对Scala和函数式编程相当新,所以我在部分应用函数和函数currying的概念上遇到了一些麻烦。还有很高的机会,我会混淆一些术语,所以所有的更正都很受欢迎。

注意:我正在使用Scala Play框架,但这更像是Scala问题,而不是Play问题。

给出像这样的函数

def create(id: Long, userId: Long, label: String)

我将userIdlabel作为(Int, String)元组,将id作为Long。{基本上我要做的就是将id和元组同时传递给函数。

现在,我已经读过将元组传递给函数可以完成这样的事情

scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int

scala> (f _).tupled((2, "Hello"))
res0: Int = 0

并且可以部分应用这样的函数

scala> def f(a: Int, b: String) = 0
f: (a: Int, b: String)Int

scala> val ff = f(_: Int, "Hello")
ff: Int => Int = <function1>

scala> ff(2)
res1: Int = 0

所以我最初的想法是将这两个概念结合起来就像这样

scala> def g(a: Long, b: Int, c: String) = 0
g: (a: Long, b: Int, c: String)Int

scala> val h = g(1, _: Int, _: String)
h: (Int, String) => Int = <function2>

scala> (h _).tupled((2, "Hello"))

然而,这会导致错误

<console>:10: error: _ must follow method; cannot follow h.type
              (h _).tupled((1, "Hello"))
               ^

所以我的问题首先是为什么这不起作用,因为对我来说这是有道理的。其次,我将如何实现这一效果?

感谢您的帮助!

1 个答案:

答案 0 :(得分:3)

请勿将其抽象两次:不要对h进行冗余和下划线,因为它在部分应用后已经是一个功能:

scala> def create(a: Long, b: Int, c: String) = 0
create: (a: Long, b: Int, c: String)Int

scala> val h = create(1, _: Int, _: String)
h: (Int, String) => Int = <function2>

scala> h.tupled((1, "Hello"))
res0: Int = 0

更深入地,tupled是在函数上定义的(object表示Function,如Int => String),而不是方法(如def f(i: Int): String) - 所以有时您需要将方法转换为函数 - 它被称为eta-expansion(或更普遍的eta-abstraction)。当你进行部分申请时 - 自动完成eta-expansion(你已经拥有(Int, String) => Int) - 所以你不必再做两次。

有关详细信息,请参阅The differences between underscore usage in these scala's methodsDifference between method and function in Scala