Scala函数式编程基础二

Scala函数式编程基础

闭包

当一个函数的执行依赖于声明在函数外部的一个或者多个变量时,则称这个函数为闭包,因为它包含了调用此函数的语句所在的上下文环境,函数改变了外部变量的生命周期。很多人以为写一个闭包函数首先要有一个函数嵌套,然后内部函数引用外部函数的变量,然后返回的是一个函数,大概是这样:

object closure {
  def main(args: Array[String]): Unit = {
    println(makeAdd()(1))
  }
  def makeAdd() = {
    val more = 10
    (x: Int) => x + more
  }
}

其实这里的外部函数主要是为了隐藏变量,限制变量的作用范围,并不是必须的;把外部变量more改为makeAdd的参数时:

object closure {
  def main(args: Array[String]): Unit = {
    println(makeAdd(12)(13))
  }
def makeAdd(more : Int) = (x: Int) => x + more
}

这实际上就是柯里化函数的样式了。闭包实际上不是必须要嵌套函数的,比如:

var more = 10
val addMore = (x:Int)=> x+ more

偏函数

有时候一个函数在特殊的应用场景下,部分参数可能始终取相同的值,为了避免每次都提供这些相同的参数值,可以该函数来定义一个新的函数,这就是偏应用函数。例如:

def sum(a:Int,b:Int,c:Int) = a+ b+ c
val a = sum(1,_:Int,_:Int) 
a(2,3)   //相当于sum(1,2,3)
val b = sum _   //进行ETA展开,方法转换为一个函数注意sum后有空格
b(1,2,3)   //相当于sum(1,2,3)

Curry化

Curry化函数是指那种带有多个参数列表且每个参数列表只包含一个参数的函数;例如:

//方法可以有多个参数列表
def multiplier(factor:Int)(x:Int) = x * factor
val byTwo = multiplier(2)_   //第一个参数固定为2,保留mutilplier第二个参数的偏应用函数
byTwo(5)    //相当于mutiplier(2,5)

实际上,可以通过Curry化过程,将一个多参数的普通函数转化为Curry化函数,例如:

def plainMultiplier(x:Int,y:Int) = x * y   //带有两个参数的普通函数
val curriedMutiplier = (plainMutiplier _).curried    //先将方法进行ETA展开,然后进行Curry化
//curriedMultiplier:Int => (Int => Int)=
curriedMultiplier(2)(3)  //结果和curriedMultiplier(2,3)相同

由curriedMultiplier的结构可以看出,普通函数和Curry化函数的区别在于普通函数将参数传入后函数是一次运行并得到结果,而Curry函数是惰性求值,先传入第一个参数作用于函数,此时还未真正求值,然后传入第二个参数作用于内部的函数,在内部函数中进行求值,最终返回结果。这就是前面的闭包,第一个参数相当于外部局部变量,第二个参数所在的内部函数依赖于它(Curry化函数被scala转化为了闭包的)。

你可能感兴趣的:(Scala函数式编程基础二)