函数式编程简介

第四代编程语言实现了更高层次的抽象,让程序员可以把更多乏味单调的任务托付给语言运行时,从而把时间花在更高层次的抽象上,多考虑怎样解决复杂的业务场景,少去费心复杂的底层运作。

函数式编程 是一种编程范式,它既是从特定角度去看待问题的思维框架,又是实现思维图景的配套工具。现代编程语言常常是多范式 的,支持多种多样的编程范式,如面向对象、元编程、函数式、过程式,等等。

函数式编程将程序描述为表达式和变换,以数学方程的形式建立模型,并且尽量避免可变的状态。函数式编程语言对问题的归类不同于命令式语言。

对待代码重用的方式

  • 面向对象语言喜欢大量地建立有很多操作的各种数据结构,函数式语言也有很多的操作,但对应的数据结构却很少。
  • 面向对象语言鼓励我们建立专门针对某个类的方法,我们从类的关系中发现重复出现的模式并加以重用。函数式语言的重用表现在函数的通用性上,它们鼓励在数据结构上使用各种共通的变换,并通过高阶函数来调整操作以满足具体事项的要求。

编程风格

  • 命令式编程是按照“程序是一系列改变状态的命令”来建模的一种编程风格。传统的for 循环是命令式风格的绝好例子:先确立初始状态,然后每次迭代都执行循环体中的一系列命令。
  • 命令式编程风格常常迫使我们出于性能考虑,把不同的任务交织 起来,以便能够用一次循环来完成多个任务。
  • 函数式语言提倡在有限的几种关键数据结构(如list 、set 、map )上运用针对这些数据结构高度优化过的操作,以此构成基本的运转机构。开发者再根据具体用途,插入自己的数据结构和高阶函数去调整机构的运转方式。
  • 函数式编程用map() 、filter() 这些高阶函数把我们解放出来,让我们站在更高的抽象层次上去考虑问题,把问题看得更清楚。

面向对象编程通过封装不确定因素来使代码能被人理解;函数式编程通过尽量减少不确定因素来使代码能被人理解。

具有普遍意义的基本构造单元

  • 筛选(filter)是列表的一种基本操作:根据用户定义的条件来筛选列表中的条目,并由此产生一个较小的新列表。
  • 映射 (map)操作对原集合的每一个元素执行给定的函数,从而变换成一个新的集合。
  • 折叠/化约(reduce 和fold) 操作在功能上大致重合,但根据具体的编程语言而有微妙的区别。两者都用一个累积量 (accumulator)来“收集”集合元素。reduce 函数一般在需要为累积量设定一个初始值的时候使用,而fold 起始的时候累积量是空的。函数在操作集合的时候可以有不同的次序,这点会体现在相应的函数命名上(如foldLeft 和foldRight )。这里提到的任何一种操作,都不会改变原集合。

权责让渡

  • 迭代让位于高阶函数
    • 理解掌握的抽象层次永远要比日常使用的抽象层次更深一层。
  • 闭包
  • 柯里化 (currying)和函数的部分施用 (partial application)常用于函数工厂、Template Method、隐含参数
    • 柯里化指的是从一个多参数函数变成一连串单参数函数的变换。它描述的是变换的过程,不涉及变换之后对函数的调用。调用者可以决定对多少个参数实施变换,余下的部分将衍生为一个参数数目较少的新函数。
    • 部分施用指通过提前代入一部分参数值,使一个多参数函数得以省略部分参数,从而转化为一个参数数目较少的函数。这种技法叫作“部分施用”,顾名思义,就是让函数先作用于其中一些参数,经过部分的求解,结果返回一个由余下参数构成签名的函数。
  • 递归
  • Stream和作业顺序重排

用巧不用蛮

很多函数式编程构造的目的只有一个:从频繁出现的场景中消灭掉烦人的实现细节。

  • 记忆 (memoization)指的是在函数级别上对需要多次使用的值进行缓存的机制。只有纯 (pure)函数才可以适用缓存技术。纯函数是没有副作用的函数:它不引用其他值可变的类字段,除返回值之外不设置其他的变量,其结果完全由输入参数决定。

  • 缓求值 (laziness)指尽可能地推迟求解表达式。缓求值的集合不会预先算好所有的元素,而是在用到的时候才落实下来,这样做有几个好处。

    • 昂贵的运算只有到了绝对必要的时候才执行。
    • 我们可以建立无限大的集合,只要一直接到请求,就一直送出元素。
    • 按缓求值的方式来使用映射、筛选等函数式概念,可以产生更高效的代码。

函数式语言中的设计模式

模式已被吸收成为语言的一部分,因此结合设计模式的优势和函数式范式的优点,采用复合型方法更佳。

模式中描述的解决办法在函数式范式下依然成立,但实现细节有所变化。

由于在新的语言或范式下获得了原本没有的能力,产生了新的解决方案(例如很多问题都可以用元编程干净利落地解决,但Java没有元编程能力可用)。

函数级别的重用与模式的关系:

  • 复合(composition)
  • Template Method模式
  • Strategy模式
  • Flyweight模式和记忆
  • Factory模式和柯里化

对比两种在编程世界中流行的抽象形态,一种是复合型 (composable)抽象,另一种是上下文型 (contextual)抽象。基于插件的架构可以作为上下文型 抽象的代表。

复合型的构建工具(对时间、复杂度、用途)的适应性要好于上下文型的构建工具。

参考

版权声明:本文为博主原创文章,转载请注明出处。 旭日酒馆