函数式编程(五)

若是你前面都看完了跟到了这里,我只能说你很棒棒,不过我不得不说,这才刚刚开始。前面咱们已经知道如何书写函数式的程序了,可是咱们还没提到控制流(control flow)、异常处理(error handling)、异步操做(asynchronous actions)和状态(state)呢?编程

容器

容器为函数式编程里普通的变量、对象、函数提供了一层极其强大的外衣,赋予了它们一些很惊艳的特性
按照咱们的惯例,先从最简单的容器入手。数组

var Container = function(x) {
  this.__value = x;
}

Container.of = function(x) { return new Container(x); };

试着执行如下Container.of(3),看看输出的值。
jQuery $(...) 返回的对象并非一个原生的 DOM 对象,而是对于原生对象的一种封装,某种意义上就是一个“容器”。
咱们接着添加一个map方法异步

Container.prototype.map = function(f){
  return Container.of(f(this.__value))
}

Container.of(3)
    .map(x => x + 1)                //=> Container(4)
    .map(x => 'Result is ' + x);    //=> Container('Result is 4')

这个跟前面咱们提到的数组操做的map方法很是相似,数组的map方法返回一个新的数组,Container的map方法返回一个新的Container。async

上面的这个具备map方法的容器就是咱们接下来要引出来的函子。函数式编程

Functor(函子)是实现了 map 并遵照一些特定规则的容器类型。函数

Functor 是一个对于函数调用的抽象,咱们赋予容器本身去调用函数的能力。当 map 一个函数时,咱们让容器本身来运行这个函数,这样容器就能够自由地选择什么时候何地如何操做这个函数,以至于拥有惰性求值、错误处理、异步调用等等很是牛掰的特性
接着咱们看看牛掰的Functor能为咱们作什么this

var Maybe = function(x) {
  this.__value = x;
}

Maybe.of = function(x) {
  return new Maybe(x);
}

Maybe.prototype.isNothing = function() {
  return (this.__value === null || this.__value === undefined);
}

Maybe.prototype.map = function(f) {
  return this.isNothing() ? Maybe.of(null) : Maybe.of(f(this.__value));
}

Maybe.of("Malkovich Malkovich").map(match(/a/ig));
//=> Maybe(['a', 'a'])

Maybe.of(null).map(match(/a/ig));
//=> Maybe(null),代码并无报错,咱们在对函数调用时,检查了函数是否为空

咱们若是不想一值.map .map, 能够用柯里化函数对上面的代码稍微改进一下prototype

var map = curry((f, any_functor_at_all) => any_functor_at_all.map(f));

错误处理code

var Left = function(x) {
  this.__value = x;
}
var Right = function(x) {
  this.__value = x;
}

Left.of = function(x) {
  return new Left(x);
}
Right.of = function(x) {
  return new Right(x);
}

Left.prototype.map = function(f) {
  return this;
}
Right.prototype.map = function(f) {
  return Right.of(f(this.__value));
}
var getAge = user => user.age ? Right.of(user.age) : Left.of("ERROR!");

getAge({name: 'stark', age: '21'}).map(age => 'Age is ' + age);

getAge({name: 'stark'}).map(age => 'Age is ' + age);

//Left 会终端机链式调用

最后来看下咱们不得不作的IO操做对象

let readLocalStorage = () => {
    return window.localStorage;
}

机智的改形成纯函数

let readLocalStorage = () => {
    return () => {window.localStorage};
}

然而并无什么软用

var IO = function(f) {
  this.__value = f;
}

IO.of = function(x) {
  return new IO(() => x);
}

IO.prototype.map = function(f) {
  return new IO(_.compose(f, this.__value));
}
var io_window = new IO(function(){ return window; });

io_window.map(function(win){ return win.innerWidth });

io_window.map(_.prop('location')).map(_.prop('href')).map(split('/'));


var $ = function(selector) {
  return new IO(function(){ return document.querySelectorAll(selector); });
}

$('#myDiv').map(head).map(function(div){ return div.innerHTML; });
相关文章
相关标签/搜索