第五章 代码组合(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' ```
';