函數式編程(五)

若是你前面都看完了跟到了這裏,我只能說你很棒棒,不過我不得不說,這纔剛剛開始。前面咱們已經知道如何書寫函數式的程序了,可是咱們還沒提到控制流(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; });
相關文章
相關標籤/搜索