🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## 概述 不管是 functor 还是 Maybe 存进去的值只有通过 `map` 进行操作 ## functor > functor 是实现了`map`函数并遵守一些特定规则的容器类型。 * functor*就是一个签了合约的接口 ``` var Contianer=function (x) { this.__value=x } Contianer.of=function (x) { return new Contianer(x) } Contianer.prototype.map=function(f){ return Contianer.of(f(this.__value)) } // test Container.of(2).map(function(two){ return two + 2 }) //=> Container(4) Container.of("flamethrowers").map(function(s){ return s.toUpperCase() }) //=> Container("FLAMETHROWERS") Container.of("bombs").map(concat(' away')).map(_.prop('length')) //=> Container(10) ``` 把值装进一个容器,而且只能使用`map`来处理它,这么做的理由到底是什么呢? 答案是抽象,对于函数运用的抽象。当`map`一个函数的时候,我们请求容器来运行这个函数。不夸张地讲,这是一种十分强大的理念 此函数声明一个使用Functor 的函数作为参数 ``` // map :: Functor f => (a -> b) -> f a -> f b var map = curry(function(f, any_functor_at_all) { return any_functor_at_all.map(f); }); ``` ## Maybe `Maybe`与`map`的不同处在于,`Maybe`会先检查自己的值是否为空,然后才调用传进来的函数 ``` 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)); } // test Maybe.of("Malkovich Malkovich").map(match(/a/ig)); //=> Maybe(['a', 'a']) Maybe.of(null).map(match(/a/ig)); //=> Maybe(null) Maybe.of({name: "Boris"}).map(_.prop("age")).map(add(10)); //=> Maybe(null) Maybe.of({name: "Dinah", age: 14}).map(_.prop("age")).map(add(10)); //=> Maybe(24) ``` ### 用例 `Maybe`最常用在那些可能会无法成功返回结果的函数中 实例1: ``` // safeHead :: [a] -> Maybe(a) var safeHead = function(xs) { return Maybe.of(xs[0]); }; var streetName = compose(map(_.prop('street')), safeHead, _.prop('addresses')); streetName({addresses: []}); // Maybe(null) streetName({addresses: [{street: "Shady Ln.", number: 4201}]}); // Maybe("Shady Ln.") ``` - `safeHead`与一般的`_.head`类似,但是增加了类型安全保证 实例2: 有时候函数可以明确返回一个`Maybe(null)`来表明失败 ``` // withdraw :: Number -> Account -> Maybe(Account) var withdraw = curry(function(amount, account) { return account.balance >= amount ? Maybe.of({balance: account.balance - amount}) : Maybe.of(null); }); // finishTransaction :: Account -> String var finishTransaction = compose(remainingBalance, updateLedger); // <- 假定这两个函数已经在别处定义好了 // getTwenty :: Account -> Maybe(String) var getTwenty = compose(map(finishTransaction), withdraw(20)); getTwenty({ balance: 200.00}); // Maybe("Your balance is $180.00") getTwenty({ balance: 10.00}); // Maybe(null) ``` ## 释放容器里的值 ``` // maybe :: b -> (a -> b) -> Maybe a -> b var maybe = curry(function(x, f, m) { return m.isNothing() ? x : f(m.__value); }); // getTwenty :: Account -> String var getTwenty = compose( maybe("You're broke!", finishTransaction), withdraw(20) ); getTwenty({ balance: 200.00}); // "Your balance is $180.00" getTwenty({ balance: 10.00}); // "You're broke!" ```