一直追求”见字如面“、“代码自解释”的我,终于遇到了一种编程范式:函数式编程,高度抽象的语法使得代码如诗一样,总结一下学习成果。
主角
Introduction · 函数式编程指北 (gitbooks.io)
Why ?
计算机语言根据抽象层次划分了等级,底层的语言如,C、汇编,其更贴近计算机,抽象程度低,执行效率高;而高级的语言如 Java,PHP,C#,其更贴近计算,抽象程度较高,执行效率低,而函数式编程则是在其基础上又一次抽象,抽象程度更高,更贴近人类思维,以至于忘记计算机内部原理也可以编码,离计算机硬件越来越远。
一些代码规范
之前看大家写代码,总有一种不明所以的感觉,那种感觉就是感觉他写的不好,又不知道怎么描述,或者用我的写法又有什么优点。了解一下函数式编程的思维,才让我豁然开朗,现在我可以说为什么不好,怎么改,改过之后好在哪里?
一些代码总有一些:可变状态(mutable state)、无限制副作用(unrestricted side effects)和无原则设计(unprincipled design)的问题。
看下面这个例子:
// 不纯的
const signUp = function(attrs) {
const user = saveUser(attrs);
welcomeUser(user);
};
const saveUser = function(attrs) {
const user = Db.save(attrs);
...
};
const welcomeUser = function(user) {
Email(user, ...);
...
};
在 saveUser
函数内,有个 Db
对象在偷偷搞小动作!假如把该函数模块化复用,明显是跑不起来的,因为缺少 Db
对象,这种代码导致不可移植,正确的写法应该是提前将所有需要的变量放到形参里,并且 signUp
应该总是返回函数,保证它是纯的,如下
// 纯的
var signUp = function(Db, Email, attrs) {
return function() {
var user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
};
var saveUser = function(Db, attrs) {
...
};
var welcomeUser = function(Email, user) {
...
};
这个例子表明,纯函数对于其依赖必须要诚实,这样我们就能知道它的目的。仅从纯函数版本的 signUp
的签名就可以看出,它将要用到 Db
、Email
和 attrs
,这在最小程度上给了我们足够多的信息。
当然还有更多原则:DRY(不要重复自己,don’t repeat yourself),高内聚低耦合(loose coupling high cohesion),YAGNI (你不会用到它的,ya ain’t gonna need it),最小意外原则(Principle of least surprise),单一责任(single responsibility)等等。
关于纯函数的的概念:第 3 章: 纯函数的好处 · 函数式编程指北 (gitbooks.io)
写代码不难,写好才难
基础
curry
首先要先搞明白curry(函数柯里化)
,它让我们的代码得以优雅地不需要一次把所有参数都传入,只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数。
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
借助 Ramda
,可以写成
import * as R from "ramda";
const add = R.curry((x, y) => {
return x + y;
});
compose
另一个是代码组合(compose)
var compose = function(f,g) {
return function(x) {
return f(g(x));
};
};
const strReverse = compose(join, reverse, split);
splitReverse("hello world!");
不写了,下周天继续研究