本文介绍了为了“结合”函数在JavaScript中的功能方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我正在学习函数式编程,我想知道是否有这样的组合功能: 函数triple(x){ return x * 3; } 函数plusOne(x){ return x + 1; } 函数isZero(x){ return x === 0; } 合并(1); // 1 combine(triple)(triple)(plusOne)(1); // 10 combine(plusOne)(triple)(isZero)( - 1); // true 如果para是一个函数,它将函数组合到自身中,if不会返回最终结果。 Thanks!解决方案这个概念来自可爱的数学。它被称为功能组合。g(y)= z $ b $(f(x))= z (g•f)(x)= z 最后一行是g x的f等于z。 组合功能的优点是消除了点。注意 g(f(x))= z 我们取一个 x 输入并得到一个 z 输出。这完全跳过了中间 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) 功能组合是创建高级函数,并保持代码的清洁。很容易明白为什么我们希望在你的Javascript中使用它。 让我们创建自己的组合函数! 好的,你听起来真的很兴奋。这里我们去... 函数triple(x){ return x * 3; } 函数plusOne(x){ return x + 1; } 函数id(x){return x; } 函数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个函数, a , b 和 c // g(x)=(a•b•c)(x) // g =(a•b•c) var g = compN([a,b,现在, compN 将会调用减少并使用我们的 id 函数对其进行初始化(原因明显稍后) reduce 的工作方式是在数组中为每个项目调用一次这个内部函数 我有意添加空白符合下面的表格 迭代gf返回解释 ---------------- -------------------------------------------------- ---------- #1 id aλx=> g(f(x))原始返回值λx=> id(a(x))代替`g`和`f` a',我们称之为a prime #2 a'bλx=> g(f(x))原始返回值λx=> a'(b(x))替代`g`和`f` b',我们称之为b素数 #3 b'cλx=> g(f(x))原始返回值λx=> b'(c(x))代替`g`和`f` c',我们称之为c prime>> c'是最终的返回值<< 所以当我们调用 compN([a,b,c]), c'是返回给我们的函数。 当我们调用该函数时会发生什么? b $ b 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)))) compN([a,b ,c])(5)=== id(a(b(c(5)))); 这真是太可爱了,但这对我的大脑来说有点难 好的,我同意,如果您和我一样,当我在3个月内返回此代码时,我我不知道该怎么办。 因此,要开始改善 compN ,让我们第一次修订 // 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 与相同 // => 6 隐藏在中减少是这个函数 function(x,y){return x + y; } 看到了吗?这看起来像一个非常基本的功能,不是吗?也可以重复使用!如果你认为添加是一个很好的名字,那么你是对的!让我们看看再次减少 函数add(x,y){return x + y; } [1,2,3] .reduce(add,0); // => 6 超级也很容易遵循。我可以随时回到那个代码并知道发生了什么。 我知道你在想什么 1 + 2 + 3 看起来非常像 a•b•c 也许如果我们从compN中提取reduce迭代器,我们可以简化compN的定义... 这是我们原来的 compN //原始函数compN(fs){ return fs.reduce(function(g,f){ return function(x){返回g(f(x)); } },id); } 让我们取出迭代器并将它称为 comp 函数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 好的,我们来看看修改过的 compN 现在 //修订1 函数compN(fs){ return fs.reduce(comp , ID); } 粗糙的改进!所以我们都完成了现在呢? Hahahahah,no。 c $ c>减少就在那里。这是一个非常有用的函数,我很确定我们可以在很多地方使用它。 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 函数compN(fs){ return reduce(comp,id)(fs); } 这看起来并不比修订好1 ... 杜,我知道!但肯定你会在每一行的末尾看到悬挂的(fs),对吗? 你不会写这个吧? //无用包装函数max(x){ return Math。 MAX(X); } max(3,1); // => 3 Duh!这与 var max = Math.max; max(3,1); // => 3 //简述函数reduce(f,i){ return function xs){ return xs.reduce(f,i); }; } 函数id(x){return x; } 函数comp(g,f){返回函数(x){ return g(f(x)); }; } //修订版3 var compN = reduce(comp,id); 那仍然是一样的吗? heck yes it does! 函数triple x){ return x * 3; } 函数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 但为什么这会更好? strong> 好吧,这很简单。当然我们有更多的代码,但现在我们有 4 可重用函数,而不仅仅是 1 。每个功能都有一个简单的任务,很容易立即识别。与原始函数相比,我们最终获得的代码更多是声明性 。这在下面会进一步强调...... 我不会在这里潜入太深,但是 ES6 让我们惊喜不已。 / /与上述相同的功能 let id = x => X; let reduce =(f,i)=> xs => xs.reduce(F,I); let comp =(g,f)=> x =>克(F(X)); 让compN = reduce(comp,id); //你的函数 let triple = x => x * 3; let plusOne = x => x + 1; //尝试一下! let g = compN([triple,triple,plusOne]); console.log(g(1)); // => 18 请将它粘贴到 Babel REPL 看看它是否有效 这就是全部,伙计们! I'm learning functional programming and I wonder if there is a way to "combine" functions like this:function triple(x) { return x * 3;}function plusOne(x) { return x + 1;}function isZero(x) { return x === 0;}combine(1); //1combine(triple)(triple)(plusOne)(1); // 10combine(plusOne)(triple)(isZero)(-1); // trueIf the para is a function, it "combines" the function into itself, and if not it will return the final result. Thanks! 解决方案 This concept comes from lovely Maths. It is called function composition. f(x) = y g(y) = z g(f(x)) = z (g•f)(x) = zThat last line is read "g of f of x equals z". What's great about composed functions is the elimination of points. Notice in g(f(x)) = z we take an x input and get a z output. This completely skips of the intermediate y. Here we say we removed the point y.So we have a composed function (g•f)(x) = z, let's set that to h(x).h(x) = (g•f)(x) = zSince (g•f) is already a function, we can remove another point, xh(x) = (g•f)(x) = z h = (g•f)Function composition is a great way to create higher-order functions and keep your code nice and clean. It's easy to see why we'd want this in your Javascript."Let's make our own composition function !"OK, you sound really excited. Here we go...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);//=> 18Evaluationtriple(triple(plusOne(1)))triple(triple(2))triple(6)18Taking this concept of building higher-order functions out of other functions, we can refactor and expand upon our definition of compNFirst let's understand how compN is evaluating things. Let's say we want to compose 3 functions, a, b, and c// g(x) = a(b(c(x)));// g(x) = (a•b•c)(x)// g = (a•b•c)var g = compN([a,b,c])Now, compN will call reduce on the array and initialize it with our id function (for reasons obvious a little later)The way reduce works is it will call this inner function once per item in our arrayfunction( g, f) { return function(x) { g(f(x)); }; }I've purposely add whitespace to have it line up with this table belowiteration 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 <<So when we call compN([a,b,c]), c' is the function that gets returned to us."Well what happens when we call that function with an arguement, such as 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 valueSo in other words...compN([a,b,c])(5) === id(a(b(c(5))));"That's fricken sweet, but that was a little hard for my brain to follow."OK, I agree, and if you're like me, when I return to this code in 3 months, I'm going to be scratching my head wondering what the hell it does.So to start improving compN, let's first revist// g(x) = a(b(c(x)));// g(x) = (a•b•c)(x)// g = (a•b•c)var g = compN([a,b,c])If we look at another example, maybe we'll get a hint[1,2,3].reduce(function(x,y) { return x + y; }, 0);//=> 6Is the same as((0 + 1) + 2) + 3//=> 6Hiding right in the middle of that reduce is this functionfunction (x,y) { return x + y; }See it? That looks like a pretty basic function, doesn't it? And reusable too! If you're thinking add is a good name for it, you'd be right! Let's look at that reduce againfunction add(x,y) { return x + y; }[1,2,3].reduce(add, 0);//=> 6That's super easy to follow, too. I could come back to that code at any time and know exactly what's going on.I know what you're thinking1 + 2 + 3Looks an awful lot likea • b • c"Maybe if we extract the reduce iterator from compN, we can simplify compN's definition..."Here's our original compN// originalfunction compN(fs) { return fs.reduce(function(g, f) { return function(x) { return g(f(x)); } }, id);}Let's take out the iterator and call it compfunction comp(g, f) { return function(x) { return g(f(x)); }}var g = comp(triple)(plusOne); // λx => triple(plusOne(x))g(1); // triple(plusOne(1))//=> 6OK, so let's see the revised compN now// revision 1function compN(fs) { return fs.reduce(comp, id);}"Gnarly improvement ! So we're all done now ?"Hahahahah, no.Look at that reduce just sitting there. That's a very useful function, and I'm pretty sure we could use that in tons of placesfunction reduce(f, i) { return function(xs) { return xs.reduce(f, i); }}reduce(add, 0)([1,2,3]); //=> 6reduce(comp, id)([a, b, c]); //=> λx => id(a(b(c(x))))That last line should be an obvious hint for the next revision to our compN function// revision 2function compN(fs) { return reduce(comp, id)(fs);}"That doesn't look much better than revision 1..."Duh, I know! But surely you see the dangling (fs) at the end of each line, right?You wouldn't write this, right?// useless wrapperfunction max(x) { return Math.max(x);}max(3,1);//=> 3Duh! That's the same asvar max = Math.max;max(3,1);//=> 3// recapfunction 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 3var compN = reduce(comp, id);"And that still works the same way?"Heck yes it does!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"But why is this better ?"Well it's simple. Sure we have a little more code, but we have 4 reusable functions now instead of just 1. Each function has a simple task which is easy to identify immediately. Compared to the original function, we end up with code that is a lot more declarative than imperative. This is even further emphasized below...Now for something really, cool. I won't dive in too deep here, but ES6 makes this amazing for us.// identical functionality as abovelet 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 functionslet triple = x => x * 3;let plusOne = x => x + 1;// try it out!let g = compN([triple, triple, plusOne]);console.log(g(1));//=> 18Go ahead and paste this into a Babel REPL to see it workAnd that's all, folks ! 这篇关于为了“结合”函数在JavaScript中的功能方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-31 13:57