Scala基础(3)- 函数 (续)

匿名函数

函数可以没有名称,可以直接赋值。如果函数有多行表达式组成,就加上大括号。这一点对匿名函数同样适用。

scala> val addOne = (x: Int) => x + 1
addOne: (Int) => Int = 

scala> addOne(1)
res4: Int = 2

注意到Scala中一切都是对象。所以addOne是一个对象。同时它又是个包含一个参数的函数。此时,函数和对象得到了统一。

偏函数应用 (Partial Application)

偏函数应用解决这样的问题:如果我们有函数是多个参数的,我们希望能固定其中某几个参数的值。在Scala中,我们可以这么做

scala> def adder(m: Int, n: Int) = m + n
adder: (m: Int,n: Int)Int
scala> val add2 = adder(2, _:Int)
add2: (Int) => Int = 

scala> add2(3)
res50: Int = 5

函数柯里化(Currying)

偏函数应用不是什么新东西,几乎所有编程语言中都可以简单地实现。但更简洁的实现是柯里化。

你可以这样定义柯里化 函数

scala> def multiply(m: Int)(n: Int): Int = m * n
multiply: (m: Int)(n: Int)Int

也可以对一个已有的函数进行转换。例如之前的adder函数

scala> (adder _).curried
res1: (Int) => (Int) => Int = 

函数柯里化依赖匿名函数,把一个多参数的函数转化为多个单参数的函数连接在一起。这样一来,语意的表达就更加丰富而直观,函数组合也更加灵活。

类型推断

一个应用场景就是类型推断。Scala类库中的foldLeft 就是这样一个例子。

def foldLeft[B](z: B)(op: (B, A) => B): B

List("").foldLeft(0)(_ + _.length)

如果使用普通的多参数函数定义

def foldLeft[B](z: B, op: (B, A) => B): B

那么,你在使用时就必须显示地表明类型。

List("").foldLeft(0, (b: Int, a: String) => a + b.length)
List("").foldLeft[Int](0, _ + _.length)

简化API

另一个currying的应用是简化API。在下面的例子中,你可以使用大括号来传递body,使得API调用层次分明。

def loop[A](n: Int)(body: => A): Unit = (0 until n) foreach (n => body)

loop(2) {
   println("hello!")
}

多阶段计算

如果你的多参数函数的计算实际上是分步骤的,某个步骤只依赖某个参数,比如下面的例子。那么柯里化会更加简单。

def v(t: Double, k: Double): Double = {
   // 只依赖于t
   val ft = f(t)

   g(ft, k)
}

v(1, 1); v(1, 2);

你可能感兴趣的:(Scala基础(3)- 函数 (续))