functional programming

2018-05-13  本文已影响0人  柒轩轩轩轩

这篇文章总结于阮一峰老师的博客
functional programming is the process of building software by composing pure functions, avoid shared state, mutable data and side-effects.

特点

1.函数是第一等公民

指的是函数与其他数据类型一样,可以赋值给其他变量,也可以作为参数传入另一个函数,或者作为别的函数的返回值

var print = function(i){ console.log(i);};
[1,2,3].forEach(print);

2. 只用expression,不用statement

expression是一个单纯的运算过程,总是有返回值,statement是执行某种操作,没有返回值

3.没有side effect

所谓side effect,指的是函数内部和外部互动,产生运算以外的其他结果。
没有side effect 意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值

4. 不修改状态

函数式编程使用参数保存状态

5. 引用透明

指的是函数的运行不依赖于外部变量或者状态,只依赖于输入的参数,任何时候只要参数相同,引用函数所得到的返回值总是相同的

范畴论

In mathematics, a category is an algebraic structure that comprises "objects" that are linked by "arrows".
我们可以把范畴想象成是一个容器,里面包括:
值和值的变形关系也就是函数

函数的合成和柯里化

函数的合成

如果一个值要经过多个函数,才能变成另一个值,就可以把所有中间步骤合并成一个函数

const compose = function (f, g) {
  return function (x) {
    return f(g(x));
  };
}

柯里化

f(x)和g(x) 合并成 f(g(x)),有一个隐藏的前提,就是f和g都只能接受一个参数

function add(x, y){
return x+y;
}
add(1, 2) //3
function addX(y){
  return function (x){
    return x + y;
  };
}
addX(2)(1) //3

一般约定,函子的标志就是容器具有map方法,该方法将容器里面的每一个值,映射到另一个容器

(new Functor(2).map(function(two){
return two+2;
});
// Functor(4)
(new Functor('flamethrowers')).map(function(s){
return s.toUpperCase();
});
//Functor('FLAMETHROWERS')
(new Functor('bomb')).map(_.concat(' away')).map(_.prop('length'));
### of方法
函数式编程一般约定,函子有一个of方法,用来生成新的容器

Functor.of = function(val){
return new Functor(val);
}

Maybe函子

函子接受各种函数,处理容器内部的值。这里就有一个问题,容器内部的值可能是一个null,而外部函数未必有处理控制的机制,如果传入空值,很可能就会出错

class Maybe extends Functor {
  map(f) {
    return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
  }
}

Either函子

Either函子内部有两个值:左值left和右值Right.
正常情况下,使用右值,左值是右值不存在时使用的默认值

class Either extends Functor {
  constructor(left, right) {
    this.left = left;
    this.right = right;
  }

  map(f) {
    return this.right ? 
      Either.of(this.left, f(this.right)) :
      Either.of(f(this.left), this.right);
  }
}

Either.of = function (left, right) {
  return new Either(left, right);
};

下面是用法

var addOne = function (x) {
  return x + 1;
};
Either.of(5, 6).map(addOne);
// Either(5, 7);
Either.of(1, null).map(addOne);
// Either(2, null);

EIther函子的另一个用途是代替try...catch,使用左值表示错误

###ap函子
函数里面包含的值,完全可能是函数

class Ap extends Functor {
ap(F) {
return Ap.of(this.val(F.val));
}
}

因此前面例子可以写成

Ap.of(addTwo).ap(Functor.of(2))
// Ap(4)

function add(x) {
return function (y) {
return x + y;
};
}

Ap.of(add).ap(Maybe.of(2)).ap(Maybe.of(3));
// Ap(5)

### Monad函子
Monad函子的作用是,总是返回一个单层的函子,它有一个flatMap方法,与map方法作用相同,唯一的区别是如果生成了一个嵌套函子,它会取出后者内部的值,保证返回的永远是一个单层的容器,不会出现嵌套的情况。
### IO操作
Monad 函子的重要应用,就是实现 I/O (输入输出)操作。

I/O 是不纯的操作,普通的函数式编程没法做,这时就需要把 IO 操作写成Monad函子,通过它来完成。

var fs = require('fs');

var readFile = function(filename) {
return new IO(function() {
return fs.readFileSync(filename, 'utf-8');
});
};

var print = function(x) {
return new IO(function() {
console.log(x);
return x;
});
}

上一篇下一篇

猜你喜欢

热点阅读