4
scala> def a(i:Int)(j:Int) = i * j
a: (i: Int)(j: Int)Int

scala> def b(i:Int, j:Int) = i * j
b: (i: Int, j: Int)Int

这两个定义非常相似,它们(在我看来)做同样的事情。

除了定义一个接收隐式参数或代码块作为参数的函数之外,还有什么理由使用第一种定义样式?

4

3 回答 3

8

这是我长期以来编制的清单:

1)跨多个参数列表的类型解析

class ResourceManager {
  type Resource

  def open: Resource = ???
}

class ResourceManagerTest {
  // Does not compile: def test1(rm: ResourceManager, r: rm.Resource) = ???

  // Compiles: This way the type can be resolved
  def test2(rm: ResourceManager)(r: rm.Resource) = ???
}

2)类型推断,其中较早的参数可以为以后的参数“锁定”类型参数(感谢 Myserious Dan)

  def foo1[A](x: A, f: A => Int) = ???

  def foo2[A](x: A)(f: A => Int) = ???

  def foo1foo2Demo() {
    // This will always demand a type annotation on any anonymous function
    // you pass in:
    foo1(1, (i: Int) => i * i)

    // Does not compile: foo1(1, i => i * i)

    // Type not required
    foo2(2)(i => i * i)
  }

3)类语法语言扩展

object MultipleArgumentListsDemo {
  // This style of function definition allows syntax-like language extensions
  @tailrec
  def myWhile(conditional: => Boolean)(f: => Unit) {
    if (conditional) {
      f
      myWhile(conditional)(f)
    }
  }

  def myWhileDemo() {
    var count = 0
    myWhile(count < 5) {
      count += 1
      println(count)
    }
  }

4)同时具有隐式和非隐式参数,因为隐式是整个参数列表的修饰符:

  def f[A](x: A)(implicit mf: Manifest[A]) {
  }

5) 一个参数列表中的参数值可用于计算另一个参数列表中的默认值,但不能用于计算同一个参数列表中的默认值。

  def g(x: Int)(y: Int = x * 2) = {
    x + y
  }

6)多个重复的参数列表(“varargs”)

  def h(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum

7)部分应用

  def i() {
    val foop = h(1, 2, 3)(4, 5, 6, 7, 9) _
    println(foop(Seq(10, 11)))
 }

由于我在编译该列表时没有跟踪我的来源:部分或所有示例可能是从其他地方复制的(关于 SO 的其他问题),所以请记下,我将添加关于哪里的参考它来自。

于 2013-08-08T10:13:34.137 回答
3

以这种方式“currying”函数的主要原因是启用部分应用程序:

scala> val c = a(5) _
c: Int => Int = <function1>

这里 c 是一个函数,它接受单个 int 并返回将该 int 与 5 相乘的结果。您可能会在一个方法中设置 c,然后将其传递给另一个方法,该方法期望函数接受一个 Int 参数。在这种情况下有点微不足道,但对于一系列用途来说非常灵活。

于 2013-08-08T01:08:09.863 回答
1

除了支持柯里化之外,它还有助于类型推断:如果所有内容都在一个参数列表中,有时编译器无法推断出正确的类型,但如果您拆分依赖于其他参数绑定的部分,它就可以工作。一个典型的例子是foldLeft:尝试用一个参数列表来实现它,然后在某些情况下编译器需要类型注释。

于 2013-08-08T08:44:21.503 回答