【Scala】高阶函数和柯里化

高阶函数

在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:

- 接受一个或多个函数作为输入
- 输出一个函数

在数学中它们也叫做算子(运算符)或泛函。微积分中的导数就是常见的例子,因为它映射一个函数到另一个函数。

高阶函数的例子

假设有一个函数对给定两个数区间中的所有整数求和:

def sumInts(a: Int, b: Int): Int = 
  if(a > b) 0 else a + sumInts(a + 1, b)

如果现在要求连续整数的平方和:

def square(x: Int): Int = x * x
def sumSquares(a: Int, b: Int): Int = 
  if(a > b) 0 else square(a) + sumSquares(a + 1, b)

如果要计算2的幂次的和:

def powerOfTwo(x: Int): Int = if(x == 0) 1 else 2 * powerOfTwo(x-1)
def sumPowersOfTwo(a: Int, b: Int): Int = 
  if(a > b) 0 else powerOfTwo(a) + sumPowersOfTwo(a+1, b)

上面的函数都是从a到b的f(n)的累加形式,我们可以抽取这些函数中共同的部分重新编写函数sum,其中定义的f作为一个参数传入到高阶函数sum中:

def sum(f: Int => Int, a: Int, b: Int): Int = 
  if(a > b) 0 else f(a) + sum(f, a+1, b)

def id(x: Int): Int = x
def square(x: Int): Int = x * x
def powerOfTwo(x: Int): Int = if(x == 0) 1 else 2 * powerOfTwo(x-1)

def sumInts(a: Int, b: Int): Int = sum(id, a, b)
def sumSquared(a: Int, b: Int): Int = sum(square, a, b)
def sumPowersOfTwo(a: Int, b: Int): Int = sum(powerOfTwo, a, b)

有用的高阶函数

map方法将一个函数应用到某个集合的所有元素并返回结果;foreach将函数应用到每个元素。

//打印三角形
scala> (1 to 9).map("^" * _).foreach(println _)
^
^^
^^^
^^^^
^^^^^
^^^^^^
^^^^^^^
^^^^^^^^
^^^^^^^^^

filter方法输出所有匹配某个特定条件的元素:

scala> (1 to 9).filter(_ % 2 == 0)
res14: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8)

可以通过练习使用Scala集合库中的一些常用的接受函数参数的方法来熟悉高阶函数。

柯里化

柯里化(Currying)指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。

返回函数的函数

在上面高阶函数的例子中,我们通过def sumInts(a: Int, b: Int): Int = sum(x => x, a, b)def sumSquared(a: Int, b: Int): Int = sum(x => x*x, a, b)来定义新的函数,上面这两个函数每次都要传入a和b两个参数到sum函数中,我们能否简化这些参数使得函数定义更简单呢?
我们可以通过返回函数的函数来简化参数:

def sum(f: Int => Int): (Int, Int) => Int = {
    def sumF(a: Int, b: Int): Int = 
        if(a > b) 0
        else f(a) + sumF(a+1, b)

    sumF
}

//于是得到如下定义,这样就简化了参数
def sumInts = sum(x => x)
def sumSquared = sum(x => x * x)
def sumPowersOfTwo = sum(powerOfTwo)

多个参数列表

根据上面的例子,我们能不能更加简化,省去sumIntssumSquaredsumPowersOfTwo这几个中间函数的形式呢?
通过sum(square)(1, 10)函数来替代sumSquared函数。
一般情况,这类函数的左结合的:sum(square)(1, 10) == (sum(square))(1, 10)

我们可以这样定义sum函数:

def sum(f: Int => Int)(a: Int, b: Int): Int = 
  if(a > b) 0 else f(a) + sum(f)(a + 1, b)

这使得函数编写更加简洁。

一般的,多参数函数定义为def f(args1)...(argsn) = E,
当n > 1时,等同于def f(args1)...(args n-1) = {def g(argsn) = E; g}或者def f(args1)...(args n-1) = (argsn => E)
如果重复这个过程n次,得到def f = (args1 => (args2 => ... (argsn => E) ) )
这种函数定义称为柯里化(Currying)。



文/JasonDing(简书作者)
原文链接:http://www.jianshu.com/p/5eb84e76ca6f
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值