为什么Scala每个列表都提供多个参数列表和多个参数?

Yuv*_*ory 78 scala currying partial-application

多个参数列表,例如def foo(a:Int)(b:Int) = {}每个列表的多个参数,例如def foo(a:Int, b:Int) = {},就我所知,在语义上是等效的,并且大多数函数语言只有一种方式来声明多个参数,例如F#.

我可以找到支持这两种函数定义样式的唯一原因是允许使用只有一个参数的参数列表进行类似语法的语言扩展.

def withBufferedWriter(file: File)(block: BufferedWriter => Unit)
Run Code Online (Sandbox Code Playgroud)

现在可以使用syntax-looking调用

withBufferedWriter(new File("myfile.txt")) { out =>
  out write "whatever"
  ...
}
Run Code Online (Sandbox Code Playgroud)

但是,如果没有多个参数列表,可能还有其他方法可以支持花括号的使用.

一个相关的问题:为什么在Scala中使用多个参数列表称为"currying"?Currying通常被定义为为了支持部分应用而使n-ary函数一元化的技术.但是,在Scala中,可以部分应用函数,而不会使函数的"curried"(多个参数列表,每个参数列表).

Knu*_*daa 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
Run Code Online (Sandbox Code Playgroud)

  • 既然你已经接受了这个答案,那么应该注意这只是一个例子,可能不是你的"为什么"问题的规范答案. (27认同)
  • 在支持函数类型和元组的语言中,您可以选择使用curried函数,这是不可避免的.唯一的问题是你是否提供了一些额外的语法糖来声明它们,这就是所有"参数组"的语法.没有它,你可以做同样的事情,但你必须再输入一点:`def foo [A,B,C,D,E](a:A,b:B)=(c:C) ,d:D)=>(e:E)=> ......` (3认同)
  • 对于每个人你的例子显示的内容可能并不明显.也许2个解释会产生奇迹. (3认同)
  • 这样做的一个限制是,尽管每个参数组都有一个可变长度,但必须修复组的数量(在本例中为3). (2认同)

Kev*_*ght 45

除了允许您编写看起来像语言的一部分的方法(您已经发现),值得注意的是类型推理器一次只能处理一个块.

所以在这:

def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b)
foo(1,2){_+_}
Run Code Online (Sandbox Code Playgroud)

T首先将推断为Int,然后将其用作闭包中两个下划线的类型.这就是编译器在完全类型安全的情况下知道+操作有效的方式.


Tom*_*ett 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
Run Code Online (Sandbox Code Playgroud)

当你声明单独的参数组时,这就是你正在做的那种.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>
Run Code Online (Sandbox Code Playgroud)


0__*_*0__ 22

默认参数中的返回引用:

case class Foo(bar: Int)

def test(f: Foo)(i: Int = f.bar) = i*i

test(Foo(3))()
Run Code Online (Sandbox Code Playgroud)


psp*_*psp 12

我知道其中一个动机是隐式参数列表."implicit"是列表的属性,而不是参数.另一个可能是案例类:只有第一个参数列表成为案例字段.