javascript 如何在 ES6 中递归地编写箭头函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25228394/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I write an arrow function in ES6 recursively?
提问by Siddharth
Arrow functions in ES6 do not have an arguments
property and therefore arguments.callee
will not work and would anyway not work in strict mode even if just an anonymous function was being used.
ES6 中的箭头函数没有arguments
属性,因此arguments.callee
即使只使用匿名函数,也不会在严格模式下工作,无论如何也不会工作。
Arrow functions cannot be named, so the named functional expression trick can not be used.
箭头函数不能命名,因此不能使用命名函数表达式技巧。
So... How does one write a recursive arrow function? That is an arrow function that recursively calls itself based on certain conditions and so on of-course?
那么...如何编写递归箭头函数?那是一个箭头函数,它根据某些条件递归调用自己,当然等等?
采纳答案by J?rg W Mittag
Writing a recursive function without naming it is a problem that is as old as computer science itself (even older, actually, since λ-calculus predates computer science), since in λ-calculus allfunctions are anonymous, and yet you still need recursion.
编写一个不命名的递归函数是一个与计算机科学本身一样古老的问题(实际上更古老,因为 λ-演算早于计算机科学),因为在 λ-演算中所有函数都是匿名的,但您仍然需要递归。
The solution is to use a fixpoint combinator, usually the Y combinator. This looks something like this:
解决方案是使用固定点组合器,通常是 Y 组合器。这看起来像这样:
(y =>
y(
givenFact =>
n =>
n < 2 ? 1 : n * givenFact(n-1)
)(5)
)(le =>
(f =>
f(f)
)(f =>
le(x => (f(f))(x))
)
);
This will compute the factorial of 5
recursively.
这将5
递归计算阶乘。
Note: the code is heavily based on this: The Y Combinator explained with JavaScript. All credit should go to the original author. I mostly just "harmonized" (is that what you call refactoring old code with new features from ES/Harmony?) it.
注意:代码主要基于此:Y Combinator 用 JavaScript 解释。所有的功劳都应该归原作者所有。我主要只是“协调”(这就是你所说的用 ES/Harmony 的新功能重构旧代码?)它。
回答by Ortomala Lokni
Claus Reinke has given an answer to your question in a discussion on the esdiscuss.org website.
Claus Reinke 在esdiscuss.org 网站上的讨论中回答了您的问题。
In ES6 you have to define what he calls a recursion combinator.
在 ES6 中,您必须定义他所谓的递归组合器。
let rec = (f)=> (..args)=> f( (..args)=>rec(f)(..args), ..args )
If you want to call a recursive arrow function, you have to call the recursion combinator with the arrow function as parameter, the first parameter of the arrow function is a recursive function and the rest are the parameters. The name of the recursive function has no importance as it would not be used outside the recursive combinator. You can then call the anonymous arrow function. Here we compute the factorial of 6.
如果要调用递归箭头函数,必须以箭头函数为参数调用递归组合子,箭头函数的第一个参数为递归函数,其余为参数。递归函数的名称并不重要,因为它不会在递归组合器之外使用。然后您可以调用匿名箭头函数。这里我们计算 6 的阶乘。
rec( (f,n) => (n>1 ? n*f(n-1) : n) )(6)
If you want to test it in Firefox you need to use the ES5 translation of the recursion combinator:
如果你想在 Firefox 中测试它,你需要使用递归组合器的 ES5 翻译:
function rec(f){
return function(){
return f.apply(this,[
function(){
return rec(f).apply(this,arguments);
}
].concat(Array.prototype.slice.call(arguments))
);
}
}
回答by Ortomala Lokni
It looks like you can assign arrow functions to a variable and use it to call the function recursively.
看起来您可以将箭头函数分配给变量并使用它来递归调用该函数。
var complex = (a, b) => {
if (a > b) {
return a;
} else {
complex(a, b);
}
};
回答by Bergi
Use a variable to which you assign the function, e.g.
使用您分配函数的变量,例如
const fac = (n) => n>0 ? n*fac(n-1) : 1;
If you really need it anonymous, use the Y combinator, like this:
如果您真的需要匿名,请使用Y 组合器,如下所示:
const Y = (f) => ((x)=>f((v)=>x(x)(v)))((x)=>f((v)=>x(x)(v)))
… Y((fac)=>(n)=> n>0 ? n*fac(n-1) : 1) …
(丑是不是?)
回答by Bill Barry
A general purpose combinator for recursive function definitions of any number of arguments (without using the variable inside itself) would be:
用于任意数量参数的递归函数定义的通用组合器(不使用自身内部的变量)将是:
const rec = (le => ((f => f(f))(f => (le((...x) => f(f)(...x))))));
This could be used for example to define factorial:
例如,这可以用于定义阶乘:
const factorial = rec( fact => (n => n < 2 ? 1 : n * fact(n - 1)) );
//factorial(5): 120
or string reverse:
或字符串反转:
const reverse = rec(
rev => (
(w, start) => typeof(start) === "string"
? (!w ? start : rev(w.substring(1), w[0] + start))
: rev(w, '')
)
);
//reverse("olleh"): "hello"
or in-order tree traversal:
或有序树遍历:
const inorder = rec(go => ((node, visit) => !!(node && [go(node.left, visit), visit(node), go(node.right, visit)])));
//inorder({left:{value:3},value:4,right:{value:5}}, function(n) {console.log(n.value)})
// calls console.log(3)
// calls console.log(4)
// calls console.log(5)
// returns true
回答by Eli Barzilay
TL;DR:
特尔;博士:
const rec = f => f((...xs) => rec(f)(...xs));
There are many answers here with variations on a proper Y-- but that's a bit redundant... The thing is that the usual way Y is explained is "what if there is no recursion", so Y itself cannot refer to itself. But since the goal here is a practicalcombinator, there's no reason to do that. There's this answerthat defines rec
using itself, but it's complicated and kind of ugly since it adds an argument instead of currying.
这里有很多答案,其中有一个适当的 Y 的变化——但这有点多余......问题是 Y 的通常解释方式是“如果没有递归会怎样”,所以 Y 本身不能指代自己。但因为这里的目标是一个实用的组合器,所以没有理由这样做。有一个定义using 本身的答案rec
,但它很复杂而且有点丑,因为它添加了一个参数而不是柯里化。
The simple recursively-defined Y is
简单的递归定义的 Y 是
const rec = f => f(rec(f));
but since JS isn't lazy, the above adds the necessary wrapping.
但由于 JS 并不懒惰,因此上面添加了必要的包装。
回答by philipp
var rec = () => {rec()};
rec();
Would that be an option?
那会是一个选择吗?
回答by Jonathan Lerner
Since arguments.callee
is a bad option due to deprecation/doesnt work in strict mode, and doing something like var func = () => {}
is also bad, this a hack like described in this answer is probably your only option:
由于arguments.callee
弃用/在严格模式下不起作用var func = () => {}
,这是一个糟糕的选择,并且做类似的事情也很糟糕,因此这个答案中描述的黑客可能是您唯一的选择:
回答by Ricardo Freitas
This is a version of this answer, https://stackoverflow.com/a/3903334/689223, with arrow functions.
这是这个答案的一个版本,https://stackoverflow.com/a/3903334/689223,带有箭头功能。
You can use the U
or the Y
combinator. Y combinator being the simplest to use.
您可以使用U
或Y
组合器。Y 组合器是最容易使用的。
U
combinator, with this you have to keep passing the function:
const U = f => f(f)
U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))
U
组合器,有了这个,你必须继续传递函数:
const U = f => f(f)
U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))
Y
combinator, with this you don't have to keep passing the function:
const Y = gen => U(f => gen((...args) => f(f)(...args)))
Y(selfFn => arg => selfFn('to infinity and beyond'))
Y
组合器,有了这个,你不必继续传递函数:
const Y = gen => U(f => gen((...args) => f(f)(...args)))
Y(selfFn => arg => selfFn('to infinity and beyond'))
回答by H. Saleh
I found the provided solutions really complicated, and honestly couldn't understand any of them, so i thought out a simpler solution myself (I'm sure it's already known, but here goes my thinking process):
我发现提供的解决方案真的很复杂,老实说,其中任何一个都看不懂,所以我自己想出了一个更简单的解决方案(我确定它已经知道了,但我的思考过程是这样的):
So you're making a factorial function
所以你在做一个阶乘函数
x => x < 2 ? x : x * (???)
the (???) is where the function is supposed to call itself, but since you can't name it, the obvious solution is to pass it as an argument to itself
(???) 是函数应该调用自身的地方,但由于您无法命名它,显而易见的解决方案是将其作为参数传递给自身
f => x => x < 2 ? x : x * f(x-1)
This won't work though. because when we call f(x-1)
we're calling this function itself, and we just defined it's arguments as 1) f
: the function itself, again and 2) x
the value. Well we do have the function itself, f
remember? so just pass it first:
不过这行不通。因为当我们调用时,f(x-1)
我们正在调用这个函数本身,我们只是将它的参数定义为 1) f
:函数本身和 2)x
值。好吧,我们确实有函数本身,f
记得吗?所以只需先通过它:
f => x => x < 2 ? x : x * f(f)(x-1)
^ the new bit
And that's it. We just made a function that takes itself as the first argument, producing the Factorial function! Just literally pass it to itself:
就是这样。我们刚刚创建了一个将自身作为第一个参数的函数,生成了 Factorial 函数!只需字面上将它传递给自己:
(f => x => x < 2 ? x : x * f(f)(x-1))(f => x => x < 2 ? x : x * f(f)(x-1))(5)
>120
Instead of writing it twice, you can make another function that passes it's argument to itself:
您可以创建另一个将其参数传递给自身的函数,而不是编写两次:
y => y(y)
and pass your factorial making function to it:
并将您的阶乘函数传递给它:
(y => y(y))(f => x => x < 2 ? x : x * f(f)(x-1))(5)
>120
Boom. Here's a little formula:
繁荣。这是一个小公式:
(y => y(y))(f => x => endCondition(x) ? default(x) : operation(x)(f(f)(nextStep(x))))
For a basic function that adds numbers from 0 to x
, endCondition
is when you need to stop recurring, so x => x == 0
. default
is the last value you give once endCondition
is met, so x => x
. operation
is simply the operation you're doing on every recursion, like multiplying in Factorial or adding in Fibonacci: x1 => x2 => x1 + x2
. and lastly nextStep
is the next value to pass to the function, which is usually the current value minus one: x => x - 1
. Apply:
对于增加的数字从0到基本功能x
,endCondition
就是当你需要停止重复,所以x => x == 0
。default
是你给出的最后一个值是否endCondition
满足,所以x => x
. operation
只是您在每次递归时执行的操作,例如在 Factorial 中乘法或在 Fibonacci: 中相加x1 => x2 => x1 + x2
。并且最后nextStep
是下一个值传递给函数,这是通常的电流值减一:x => x - 1
。申请:
(y => y(y))(f => x => x == 0 ? x : x + f(f)(x - 1))(5)
>15