函数编程优美模式( functional calisthenics)

functional calisthenics是一套类似Object calisthenics面向对象健美操的实践模式,这些规则能够让你函数编程得更好,这些严格的约束能够让你以不同角度来思考如何编写代码。

1. 副作用只发生在顶层
我们希望我们的代码都是纯函数的,这是为了避免依赖任何不纯的因素,也就是说,如果必须有不纯的函数,那么请将这些不纯的函数放置于顶层,然后尽可能与其余代码隔离,这些不纯的功能包括:
1.用户交互
2.数据库访问
3.API调用
(这三个不纯主要因为它们都可能包含可变状态,用户交互有用户会话Session可变状态,数据库是最大的可变状态保存者,API也可能包含可变状态)

2. 没有可变状态
这实际上很接近上面一条,如果我们去除函数中可变状态,我们就能创建纯函数,去除可变状态的方法有:不要重用变量,虽然这样对待代码可读性有负面影响,但是任何可变状态(变量)会导致意想不到的结果。

3.表达式(Expression)不是语句(statement)
这也是无可变状态的衍生,如果我们的函数不返回任何东西,那么这个函数内部可能存在可变状态,那么这个函数就是不纯的,我们要实现纯函数,就要让这个函数返回值。比如,SQL的insert/update语句statement是向数据库插入数据,没有任何返回结果,这种语句明显是改变了数据库数据表的数据,是不纯的,不是函数编程倡导的纯函数。

4.函数只能有一个参数
这是可能引起很多质疑的,但是如果一个函数有很多参数,这会和单一职责原则违背,Currying柯里化提供了一种将长参数降低为一系列只有一个参数函数的办法。

5.不要有显式的递归
将递归和你需要执行的逻辑分离隐藏起来。(类似foreach这种最好使用函数编程语言提供的Monad等方式实现)

6.抽象的最大层次
函数应该尽可能采取抽象的最高层次,比如,如果List是Enumerble的特殊情况,那么函数就应该采取Enumerble。

7.使用无限序列
如果你你的函数使用或返回一系列数据,那么写这个函数的方式不要排除无限序列,而是允许tail尾递归。

8. No if
尽可能避免使用if语句,正如Samir所说:
"if" is just a special case of pattern matching anyway
if 只是模式匹配的特殊情况

9.为一切取名
我们应当为比如tuple元组这样的原始类型取名,我们应该避免匿名函数和lambda。

10.使用中间变量
避免链条化函数调用,提取到中间变量。

11.不要缩写
如果我们看到一个函数名为f(),我们会进入黑暗时代,我们可以使用更具描述性的名称来帮助别人来了解代码的意图。


Ninja Ferret : Introducing functional calisthenics

不明白第5条,Monad如何解决递归问题呢?

递归的本质是堆栈操作。模拟堆栈就能解决所有的递归问题。
顺便一提,有些pascal语言无法实现递归,例如free pascal,turbo pascal。而pascal语言是广泛用于教学的语言,这是为什么呢。