functor / Maybe
最后更新于:2022-04-02 04:17:53
[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!"
```
';