這個概念來自於數學可愛。它被稱爲function composition。
f(x) = y
g(y) = z
g(f(x)) = z
(g•f)(x) = z
即最後一行被讀 「的的F x等於ž克」。 由組成的功能是點的消除。注意g(f(x)) = z
我們取x
輸入並得到z
輸出。這完全跳過了中間的y
。在這裏我們說我們刪除了點y。
所以我們有一個組成函數(g•f)(x) = z
,讓我們設置爲h(x)
。
h(x) = (g•f)(x) = z
由於(g•f)
已經是一個功能,我們可以刪除另一點,X
h(x) = (g•f)(x) = z
h = (g•f)
函數組合是創造higher-order functions,並保持你的代碼非常乾淨的好方法。很容易明白爲什麼我們希望在你的Javascript中使用它。
「讓我們自己組合功能吧!」
好吧,你聽起來真的很興奮。在這裏,我們去...
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
function id(x) { return x; }
function compN(funcs) {
return funcs.reduce(function(g, f) {
return function(x) {
return g(f(x));
}
}, id);
}
var g = compN([triple, triple, plusOne]);
// g(x) = (triple • triple • plusOne)(x)
g(1);
//=> 18
評價
triple(triple(plusOne(1)))
triple(triple(2))
triple(6)
18
如果您覺得滿意了答案,好。對於那些想探索構建更好的高階函數的人,請繼續!
以構建高階函數出的其他功能的概念,我們可以重構,並在我們的compN
定義擴大首先,讓我們瞭解如何compN
正在評估的東西。比方說,我們要組成3個功能,一個,b和C現在
// g(x) = a(b(c(x)));
// g(x) = (a•b•c)(x)
// g = (a•b•c)
var g = compN([a,b,c])
,compN
將調用陣列上reduce
,並與我們的id
函數初始化它(原因很明顯一點後來)
方式減少作品是將我們的數組中調用一次每個項目的這種內在的功能
function( g, f) { return function(x) { g(f(x)); }; }
我特意添加空格把它與此表排隊低於
iteration g f return explanation
----------------------------------------------------------------------------
#1 id a λx => g(f(x)) original return value
λx => id(a(x)) substitute for `g` and `f`
a' we'll call this "a prime"
#2 a' b λx => g(f(x)) original return value
λx => a'(b(x)) substitute for `g` and `f`
b' we'll call this "b prime"
#3 b' c λx => g(f(x)) original return value
λx => b'(c(x)) substitute for `g` and `f`
c' we'll call this "c prime"
>> c' is the final return value <<
所以,當我們調用compN([a,b,c])
,c'
是被退回的功能。
「那麼當我們通過一個參數調用該函數時會發生什麼,如c'(5)
?」
alias original x return
----------------------------------------------------------------------------
c'(5); λx => b'(c(x)) 5 b'(c(5))
b'(c(5)) λx => a'(b(x)) c(5) a'(b(c(5)))
a'(b(c(5))) λx => id(a(x)) b(c(5)) id(a(b(c(5)))) <-- final return value
換句話說
所以......
compN([a,b,c])(5) === id(a(b(c(5))));
「這是fricken甜的,但是這是一個有點辛苦爲我的大腦遵循。」
好吧,我同意,如果你和我一樣,當我在3個月內回到這段代碼時,我會抓着我的腦袋想知道它究竟做了什麼。
於是開始改善compN
,讓我們先revist
// g(x) = a(b(c(x)));
// g(x) = (a•b•c)(x)
// g = (a•b•c)
var g = compN([a,b,c])
如果我們看看另一個例子,也許我們會得到一個提示
[1,2,3].reduce(function(x,y) { return x + y; }, 0);
//=> 6
相同
((0 + 1) + 2) + 3
//=> 6
隱藏在那reduce
的中間是這個功能
function (x,y) { return x + y; }
看到了嗎?這看起來像一個非常基本的功能,不是嗎?也可以重複使用!如果你認爲add
是一個好名字,你會是對的!讓我們來看看這再次
function add(x,y) { return x + y; }
[1,2,3].reduce(add, 0);
//=> 6
這是超級容易跟隨減少了。我可以隨時回到該代碼並知道究竟是什麼發生了什麼事情。
我知道你在想什麼
1 + 2 + 3
看起來極像是
a • b • c
「也許如果我們提取compN的減少迭代器,我們可以簡化compN的定義.. 。「
這是我們的原創compN
// original
function compN(fs) {
return fs.reduce(function(g, f) {
return function(x) {
return g(f(x));
}
}, id);
}
讓我們到迭代,並調用它comp
function comp(g, f) {
return function(x) {
return g(f(x));
}
}
var g = comp(triple)(plusOne); // λx => triple(plusOne(x))
g(1); // triple(plusOne(1))
//=> 6
OK,讓我們看到修改後的compN
現在
// revision 1
function compN(fs) {
return fs.reduce(comp, id);
}
「粗糙的改善!所以,我們現在都做了什麼?」
Hahahahah,沒有。
看那個reduce
只是坐在那裏。這是一個非常有用的功能,我敢肯定,我們可以使用,在噸地方
function reduce(f, i) {
return function(xs) {
return xs.reduce(f, i);
}
}
reduce(add, 0)([1,2,3]); //=> 6
reduce(comp, id)([a, b, c]); //=> λx => id(a(b(c(x))))
最後一行應該是下一版本的明顯提示我們compN
功能
// revision 2
function compN(fs) {
return reduce(comp, id)(fs);
}
「這並不顯得比改版1好得多......」
咄,我知道了!但是,你肯定會在每行的末尾看到懸掛的(fs)
,對吧?
你不會寫這個,對吧?
// useless wrapper
function max(x) {
return Math.max(x);
}
max(3,1);
//=> 3
呃!這是一樣的
var max = Math.max;
max(3,1);
//=> 3
所以我提出最後的reivision ...
// recap
function reduce(f, i) {
return function(xs) {
return xs.reduce(f, i);
};
}
function id(x) { return x; }
function comp(g, f) {
return function(x) {
return g(f(x));
};
}
// revision 3
var compN = reduce(comp, id);
「和仍然以同樣的方式?」
是的,它確實!
function triple(x) {
return x * 3;
}
function plusOne(x) {
return x + 1;
}
var g = compN([triple, triple, plusOne]); // λx => id(triple(triple(plusOne(x))))
g(1); // id(triple(triple(plusOne(1))))
//=> 18
「但是,這是爲什麼好?「
那麼它的簡單。當然,我們有一點點更多的代碼,但我們有可重複使用的功能,現在,而不是僅僅。每個函數都有一個簡單的任務,這是很容易立即識別。相比原有的功能,我們最終得到的代碼是多了很多聲明比勢在必行,這是進一步強調了以下...
現在的東西真的很酷。我不會迪ve在這裏太深,但ES6使我們這個驚人。
// identical functionality as above
let id = x => x;
let reduce = (f,i) => xs => xs.reduce(f,i);
let comp = (g,f) => x => g(f(x));
let compN = reduce(comp, id);
// your functions
let triple = x => x * 3;
let plusOne = x => x + 1;
// try it out!
let g = compN([triple, triple, plusOne]);
console.log(g(1));
//=> 18
來吧,粘貼到一個Babel REPL以瞭解其工作
而這一切,鄉親!
什麼是'para'? –
@u_mulder參數我猜 – daremachine
問題是不明確的,在「結合」功能 – gypsyCoder