我对Scala和函数式编程相当新,所以我在部分应用函数和函数currying的概念上遇到了一些麻烦。还有很高的机会,我会混淆一些术语,所以所有的更正都很受欢迎。
注意:我正在使用Scala Play框架,但这更像是Scala问题,而不是Play问题。
给出像这样的函数
def create(id: Long, userId: Long, label: String)
我将userId
和label
作为(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"))
^
所以我的问题首先是为什么这不起作用,因为对我来说这是有道理的。其次,我将如何实现这一效果?
感谢您的帮助!
答案 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 methods,Difference between method and function in Scala。