
函数式编程
函数式编程(Functionnal programming)起源于lambda(λ)演算,这是一种在20世纪30年代开发的用于研究可计算性,“Entscheidungs”问题,函数定义、应用和递归的系统。在计算机科学中,函数式编程是一种编程范式:将计算视为数学函数并避免改变状态和数据。它是一种声明式编程范例,在函数代码中,函数输出的值仅取决于传递给函数的参数。
纯函数 Pure Functions
纯函数的三个原则
- 变量都只在函数作用域内获取, 或作为的函数的参数传入
- 引用透明(Referentially transparent)
- 相同的输入保证相同的输出(same input -> same ouput)。
1 | |
纯函数的优点
- 易于测试
- 因相同的输入总是得到相同的结果,故其结果可以缓存
- 不会产生副作用(Side effects), 不会改变被传入的数据或者其他数据
声明式编程 Declarative Style Programming
- 命令式(Imperative)编程:要实现某个功能,利用指令一步一步的要求程序执行,通过一步步修改它们的状态或值,以达到需要的结果。
1 | |
- 声明式(Declarative)编程:告诉程序我们需要什么结果,声明我们的用意,而无需提供具体的指令,所有的细节指令都将在函数内部完成。
1 | |
一等公民 First Class Functions
1 | |
闭包 Closures
广义上说,闭包就是指一个变量在他自身作用域外被使用了,就叫发生了闭包。
闭包允许我们封装某些需要的状态,特别在偏函数应用(partial application),柯里化(currying)和组合函数(composing functions)中,这使得我们可以用非常小的模块来构建高阶模式。
1 | |
1 | |
每次调用其中一个计数器时,通过改变这个变量的值,会改变这个闭包的词法环境。然而在一个闭包内对变量的修改,不会影响到另外一个闭包中的变量。
以这种方式使用闭包,提供了许多与面向对象编程相关的好处 —— 特别是数据隐藏和封装。
柯里化 Currying
Currying(柯里化) 又称部分求值。一个curring的函数首先会接受一些参数,接受了这些参数之后,该函数不会立即求值,而是继续返回另一个函数,刚才传入的参数在函数形成的闭包中被保存起来,待到函数被真正需要求值的时候,之前传入的所有参数都会被一次性用于求值。
1 | |
如果我们想统计一个月花了多少钱,利用柯里化函数,无需每天都累加之前的花费,只需在最后一天统一结算即可。
1 | |
偏函数应用 Partial Application
Partial Application(偏函数应用) 是指使用一个函数并将其应用一个或多个参数,但不是全部参数,在这个过程中创建一个新函数。
1 | |
偏函数的优点:
- 创建一个名称易懂的独立函数,调用时无需每次传入第一个参数,因为第一个参数通过bind提供了固定值。
- 当我们有一个很通用的函数,为了方便提供一个较常用的变体。如,我们有一个函数send(from, to, text),那么使用偏函数可以创建一个从当前用户发送的变体:sendTo(to, text)。
柯里化和偏函数的区别
- 柯里化 将一个多参数函数转换成多个单参数函数,也就是将一个 n 元函数转换成 n 个一元函数。
- 偏函数 固定一个函数的一个或者多个参数,也就是将一个 n 元函数转换成一个 n - x 元函数。
组合函数 Composing Functions
组合函数Compose把里面的参数都组合起来,一起调用。类似流式。
1 | |
在函数式编程里,compose是避免命令式的重要一环,compose要做到的每一个函数都是”纯”的,脏的东西交给使用者。把每个纯的函数组合到compose里面,类似于管道,每个函数就像一个插件,来处理数据流。
尾递归优化 Tail Call Optimization
1 | |
1 | |
PS: 这段时间一直忙于处理业务,心态有点浮躁。趁着元旦假期调整好心态,继续努力!