多个参数列表,例如def foo(a:Int)(b:Int) = {}
和每个列表的多个参数,例如据我所知,def foo(a:Int, b:Int) = {}
在语义上是等价的,并且大多数函数式语言只有一种声明多个参数的方法,例如F#。
我可以找到支持这两种函数定义样式的唯一原因是允许使用只有一个参数的参数列表进行类似语法的语言扩展。
def withBufferedWriter(file: File)(block: BufferedWriter => Unit)
现在可以使用语法外观调用
withBufferedWriter(new File("myfile.txt")) { out =>
out write "whatever"
...
}
但是,如果没有多个参数列表,可能还有其他方法可以支持使用花括号。
一个相关的问题:为什么在Scala中使用多个参数列表称为“currying”? Currying通常被定义为为了支持部分应用而使n-ary函数一元化的技术。但是,在Scala中,可以部分应用函数,而不会使函数的“curried”(多个参数列表,每个参数列表)。
答案 0 :(得分:76)
这使你能够做到例如:
scala> def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum
foo: (as: Int*)(bs: Int*)(cs: Int*)Int
scala> foo(1, 2, 3)(4, 5, 6, 7, 9)(10, 11)
res7: Int = 3906
答案 1 :(得分:45)
除了允许你编写看起来像语言的一部分的方法(你已经发现了),值得注意的是类型推理器一次只能处理一个块。
所以在这:
def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b)
foo(1,2){_+_}
首先将 T
推断为Int
,然后将其用作闭包中两个下划线的类型。
这就是编译器在完全类型安全的情况下知道+操作有效的方法。
答案 2 :(得分:24)
为了回答你的“相关问题”,currying只是一种将多个参数的函数(例如(A, B, C) => D
)转换为一个函数的方法,该函数接受一个参数并返回一个函数,例如: A => (B => (C => D))
(括号显示但不是必需的)。
元组化形式和咖喱形式是同构的,我们可以在它们之间自由翻译。所有这些都是等价的,但具有不同的句法含义:
(A, B, C, D, E) => F
((A, B), (C, D, E)) => F
(A, B) => (C, D, E) => F
当你声明单独的参数组时,这就是你正在做的那种。 multi-parameter-group方法是一个返回函数的方法......你可以在REPL中看到这个:
scala> def foo(a:Int, b:Int)(c:Int, d:Int, e:Int):Int = 9
foo: (a: Int,b: Int)(c: Int,d: Int,e: Int)Int
scala> foo _
res4: (Int, Int) => (Int, Int, Int) => Int = <function2>
答案 3 :(得分:21)
在默认参数中返回引用:
case class Foo(bar: Int)
def test(f: Foo)(i: Int = f.bar) = i*i
test(Foo(3))()
答案 4 :(得分:12)
我知道其中一个动机是隐式参数列表。 “implicit”是列表的属性,而不是参数。另一个可能是案例类:只有第一个参数列表成为案例字段。