chain
最后更新于:2022-04-02 04:18:12
[TOC]
## chain 函数
```
// chain :: Monad m => (a -> m b) -> m a -> m b
var chain = curry(function(f, m){
return m.map(f).join(); // 或者 compose(join, map(f))(m)
});
```
实例1
```
// map/join
var firstAddressStreet = compose(
join, map(safeProp('street')), join, map(safeHead), safeProp('addresses')
);
// chain
var firstAddressStreet = compose(
chain(safeProp('street')), chain(safeHead), safeProp('addresses')
);
// map/join
var applyPreferences = compose(
join, map(setStyle('#main')), join, map(log), map(JSON.parse), getItem
);
// chain
var applyPreferences = compose(
chain(setStyle('#main')), chain(log), map(JSON.parse), getItem
);
```
实例2
就能以一种纯函数式的方式来表示*序列*(sequence) 和*变量赋值*(variable assignment)
```
// getJSON :: Url -> Params -> Task JSON
// querySelector :: Selector -> IO DOM
getJSON('/authenticate', {username: 'stale', password: 'crackers'})
.chain(function(user) {
return getJSON('/friends', {user_id: user.id});
});
// Task([{name: 'Seimith', id: 14}, {name: 'Ric', id: 39}]);
querySelector("input.username").chain(function(uname) {
return querySelector("input.email").chain(function(email) {
return IO.of(
"Welcome " + uname.value + " " + "prepare for spam at " + email.value
);
});
});
// IO("Welcome Olivia prepare for spam at olivia@tremorcontrol.net");
Maybe.of(3).chain(function(three) {
return Maybe.of(2).map(add(three));
});
// Maybe(5);
Maybe.of(null).chain(safeProp('address')).chain(safeProp('street'));
// Maybe(null);
```
## 炫耀
实例:读取并上传一个文件
声明式代码
```
// readFile :: Filename -> Either String (Future Error String)
// httpPost :: String -> Future Error JSON
// upload :: String -> Either String (Future Error JSON)
var upload = compose(map(chain(httpPost('/uploads'))), readFile);
```
从类型签名可以看出,我们预防了三个错误
1. `readFile`使用`Either`来验证输入(或许还有确保文件名存在);
2. `readFile`在读取文件的时候可能会出错,错误通过`readFile`的`Future`表示;
3. 文件上传可能会因为各种各样的原因出错,错误通过`httpPost`的`Future`表示
所有这些操作都是在一个从左到右的线性流中完成的,是完完全全纯的、声明式的代码,是可以等式推导(equational reasoning)并拥有可靠特性(reliable properties)的代码
命令式代码
跟标准的命令式的实现对比一下
```
// upload :: String -> (String -> a) -> Void
var upload = function(filename, callback) {
if(!filename) {
throw "You need a filename!";
} else {
readFile(filename, function(err, contents) {
if(err) throw err;
httpPost(contents, function(err, json) {
if(err) throw err;
callback(json);
});
});
}
}
```
';