为什么Scala为每个列表提供多个参数列表和多个参数?
多个参数列表,例如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”? 柯里化通常被定义为为了支持部分应用而使得n元函数一元化的技术。 然而,在Scala中,可以部分应用一个函数,而不用创build一个“curried”(多个参数列表,每个参数都有一个参数)版本的函数。
它使你能够做到,例如:
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
除了允许你编写看起来像你已经发现的语言的一部分的方法之外,值得注意的是types推断器一次只能处理一个块。
所以在这个:
def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b) foo(1,2){_+_}
T
将首先被推断为Int
,然后将被用作闭包中两个下划线的types。 这是编译器如何知道,完整的types安全,+操作是有效的。
为了回答你的“相关问题”,currying只是将多个参数(例如(A, B, C) => D
)的函数转换成一个函数,它接受一个参数并返回一个函数,例如A => (B => (C => D))
(括号显示,但不是必须的)。
元组化forms和咖喱forms是同构的,我们可以在它们之间自由转换。 所有这些都是等价的,但有不同的语法含义:
(A, B, C, D, E) => F ((A, B), (C, D, E)) => F (A, B) => (C, D, E) => F
当你声明单独的参数组时,这就是你正在做的一些事情。 多参数组方法是一种返回函数的方法…您可以在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>
在默认参数中的返回引用:
case class Foo(bar: Int) def test(f: Foo)(i: Int = f.bar) = i*i test(Foo(3))()
我知道其中一个动机是隐式参数列表。 “隐式”是列表的属性,而不是参数。 另一个可能是案例类:只有第一个参数列表成为大小写字段。