How do I write an arrow function in ES6 recursively?

后端 未结 12 820
南旧
南旧 2020-12-08 06:36

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

相关标签:
12条回答
  • 2020-12-08 07:14

    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 all functions 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(
        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.

    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.

    0 讨论(0)
  • 2020-12-08 07:17

    This is a version of this answer, https://stackoverflow.com/a/3903334/689223, with arrow functions.

    You can use the U or the Y combinator. Y combinator being the simplest to use.

    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'))

    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'))

    0 讨论(0)
  • 2020-12-08 07:21

    i think the simplest solution is looking at the only thing that you don't have, which is a reference to the function itself. because if you have that then recusion is trivial.

    amazingly that is possible through a higher order function.

    let generateTheNeededValue = (f, ...args) => f(f, ...args);
    

    this function as the name sugests, it will generate the reference that we'll need. now we only need to apply this to our function

    (generateTheNeededValue)(ourFunction, ourFunctionArgs)
    

    but the problem with using this thing is that our function definition needs to expect a very special first argument

    let ourFunction = (me, ...ourArgs) => {...}
    

    i like to call this special value as 'me'. and now everytime we need recursion we do like this

    me(me, ...argsOnRecursion);
    

    with all of that. we can now create a simple factorial function.

    ((f, ...args) => f(f, ...args))((me, x) => {
      if(x < 2) {
        return 1;
      } else {
        return x * me(me, x - 1);
      }
    }, 4)
    
    -> 24
    

    i also like to look at the one liner of this

    ((f, ...args) => f(f, ...args))((me, x) => (x < 2) ? 1 : (x * me(me, x - 1)), 4)
    
    0 讨论(0)
  • 2020-12-08 07:22

    You can assign your function to a variable inside an iife

    var countdown = f=>(f=a=>{
      console.log(a)
      if(a>0) f(--a)
    })()
    
    countdown(3)
    
    //3
    //2
    //1
    //0
    
    0 讨论(0)
  • 2020-12-08 07:23
    var rec = () => {rec()};
    rec();
    

    Would that be an option?

    0 讨论(0)
  • 2020-12-08 07:23

    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 => 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:

    (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:

    (y => y(y))(f => x => x == 0 ? x : x + f(f)(x - 1))(5)
    >15
    
    0 讨论(0)
提交回复
热议问题