第五章 代码组合(compose)
最后更新于:2022-04-02 04:17:31
[TOC]
## 函数饲养
- 两个函数组合之后返回了一个新函数
- 在`compose`的定义中,`g`将先于`f`执行,因此就创建了一个从右到左的数据流。这样做的可读性远远高于嵌套一大堆的函数调用
- 让代码从右向左运行,而不是由内而外运行,我觉得可以称之为“左倾”,尽管我们可以定义一个从左向右的版本,但是从右向左执行更加能够反映数学上的含义
js版
```
var compose =function(f,g){
return function(x){
return f(g(x))
}
}
var append1=x=>x+"_1"
var append2=x=>x+"_2"
var c = compose(append1,append2)
console.log(c("ads")); //ads_2_1
```
通用 funcs compose
```
const compose =function (...funcs) {
return function (arg) {
var tmp=arg
for (let i = funcs.length-1; i >=0; i--) {
tmp = funcs[i]( tmp);
}
return tmp
}
}
const add1=x=>x+"_1"
const add2=x=>x+"_2"
const add3=x=>x+"_3"
const c = compose(add1,add2,add3)
console.log(c("hello")); // hello_3_2_1
```
golang 版
```
type composeFun func(string)string
func compose(g composeFun,f composeFun) composeFun {
return func(a string) string {
return g(f(a))
}
}
func main() {
var a = func(a string) string{
return a+"_1"
}
var b = func(a string) string{
return a+"_2"
}
c :=compose(a,b)
fmt.Printf("%+v\n", c("hello")) // hello_2_1
}
```
如果不使用compose
```
var shout = function(x){
return exclaim(toUpperCase(x));
};
```
## 结合律
```
var associative = compose(f, compose(g, h)) == compose(compose(f, g), h);
```
如
```
compose(toUpperCase, compose(head, reverse));
// 或者
compose(compose(toUpperCase, head), reverse);
var loudLastUpper = compose(exclaim, toUpperCase, head, reverse);
// 或
var last = compose(head, reverse);
var loudLastUpper = compose(exclaim, toUpperCase, last);
// 或
var last = compose(head, reverse);
var angry = compose(exclaim, toUpperCase);
var loudLastUpper = compose(angry, last);
// 更多变种...
```
## pointfree
pointfree 模式指的是,永远不必说出你的数据,无须提及将要操作的数据是什么样的
```
// 非 pointfree,因为提到了数据:word
var snakeCase = function (word) {
return word.toLowerCase().replace(/\s+/ig, '_');
};
// pointfree
var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);
```
另一个例子
```
// 非 pointfree,因为提到了数据:name
var initials = function (name) {
return name.split(' ').map(compose(toUpperCase, head)).join('. ');
};
// pointfree
var initials = compose(join('. '), map(compose(toUpperCase, head)), split(' '));
initials("hunter stockton thompson");
// 'H. S. T'
```
## debug
```
var trace = curry(function(tag, x){
console.log(tag, x);
return x;
});
var dasherize = compose(join('-'), toLower, split(' '), replace(/\s{2,}/ig, ' '));
dasherize('The world is a vampire');
// TypeError: Cannot read property 'apply' of undefined
var dasherize = compose(join('-'), toLower, trace("after split"), split(' '), replace(/\s{2,}/ig, ' '));
// after split [ 'The', 'world', 'is', 'a', 'vampire' ]
// toLower 的参数是一个数组,所以需要先用 map 调用一下它
// 修复
var dasherize = compose(join('-'), map(toLower), split(' '), replace(/\s{2,}/ig, ' '));
dasherize('The world is a vampire');
// 'the-world-is-a-vampire'
```
';