代码之家  ›  专栏  ›  技术社区  ›  Incognito

递归匿名函数?

  •  108
  • Incognito  · 技术社区  · 14 年前

    假设我有一个基本的递归函数:

    function recur(data) {
        data = data+1;
        var nothing = function() {
            recur(data);
        }
        nothing();
    }
    

    如果我有一个匿名函数,比如……

    (function(data){
        data = data+1;
        var nothing = function() {
            //Something here that calls the function?
        }
        nothing();
    })();
    

    我想要一种方法来调用调用这个函数的函数…我在某个地方看到过脚本(我不记得在哪里),它可以告诉您调用的函数的名称,但我现在记不起这些信息。

    19 回复  |  直到 6 年前
        1
  •  131
  •   Pointy    10 年前

    (function foo() { foo(); })();
    

    probably don't may not want to do this

    arguments.callee

    asyncThingWithCallback(params, (function() {
      function recursive() {
        if (timeToStop())
          return whatever();
        recursive(moreWork);
      }
      return recursive;
    })());
    

        2
  •  30
  •   zem    14 年前

    var Y = function (gen) {
      return (function(f) {
        return f(f);
      }(function(f) {
        return gen(function() {
          return f(f).apply(null, arguments);
        });
      }));
    }
    

    (Y(function(recur) {
      return function(data) {
        data = data+1;
        var nothing = function() {
          recur(data);
        }
        nothing();
      }
    })());
    

        3
  •  14
  •   Mulan    7 年前

    const U = f => f (f)
    
    U (f => (console.log ('stack overflow imminent!'), U (f)))

    const log = x => (console.log (x), x)
    
    const U = f => f (f)
    
    // when our function is applied to itself, we get the inner function back
    U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)
    // returns: (x => x > 0 ? U (f) (log (x - 1)) : 0)
    // where f is a reference to our outer function
    
    // watch when we apply an argument to this function, eg 5
    U (f => x => x > 0 ? U (f) (log (x - 1)) : 0) (5)
    // 4 3 2 1 0

    U

    const log = x => (console.log (x), x)
    
    const U = f => f (f)
    
    const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)
    
    countDown (5)
    // 4 3 2 1 0
    
    countDown (3)
    // 2 1 0

    countDown

    // direct recursion references itself by name
    const loop = (params) => {
      if (condition)
        return someValue
      else
        // loop references itself to recur...
        return loop (adjustedParams)
    }
    
    // U combinator does not need a named reference
    // no reference to `countDown` inside countDown's definition
    const countDown = U (f => x => x > 0 ? U (f) (log (x - 1)) : 0)

    const factorial = x =>
      x === 0 ? 1 : x * factorial (x - 1)
      
    console.log (factorial (5)) // 120

    factorial

    const U = f => f (f)
    
    const factorial = U (f => x =>
      x === 0 ? 1 : x * U (f) (x - 1))
    
    console.log (factorial (5)) // 120

    // self reference recursion
    const foo =         x => ...   foo (nextX) ...
    
    // remove self reference with U combinator
    const foo = U (f => x => ... U (f) (nextX) ...)
    

    the U and Y combinators explained using a mirror analogy

    // standard definition
    const Y = f => f (Y (f))
    
    // prevent immediate infinite recursion in applicative order language (JS)
    const Y = f => f (x => Y (f) (x))
    
    // remove reference to self using U combinator
    const Y = U (h => f => f (x => U (h) (f) (x)))

    U (f) f ()

    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    Y (f => (console.log ('stack overflow imminent!'),  f ()))

    Y

    const log = x => (console.log (x), x)
    
    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    const countDown = Y (f => x => x > 0 ? f (log (x - 1)) : 0)
    
    countDown (5)
    // 4 3 2 1 0
    
    countDown (3)
    // 2 1 0

    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    const factorial = Y (f => x =>
      x === 0 ? 1 :  x * f (x - 1))
    
    console.log (factorial (5)) // 120

    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    const fibonacci = Y (f => ([a, b, x]) =>
      x === 0 ? a : f ([b, a + b, x - 1]))
    
    // starting with 0 and 1, generate the 7th number in the sequence
    console.log (fibonacci ([0, 1, 7])) 
    // 0 1 1 2 3 5 8 13

    a b fibonacci (7)

    fibonacci 0 1 x f (a) (b) (x) f (a,b,x)

    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    const fibonacci = Y (f => a => b => x =>
      x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
    
    console.log (fibonacci (7)) 
    // 0 1 1 2 3 5 8 13

    range reduce map

    const U = f => f (f)
    
    const Y = U (h => f => f (x => U (h) (f) (x)))
    
    const range = Y (f => acc => min => max =>
      min > max ? acc : f ([...acc, min]) (min + 1) (max)) ([])
    
    const reduce = Y (f => g => y => ([x,...xs]) =>
      x === undefined ? y : f (g) (g (y) (x)) (xs))
      
    const map = f =>
      reduce (ys => x => [...ys, f (x)]) ([])
      
    const add = x => y => x + y
    
    const sq = x => x * x
    
    console.log (range (-2) (2))
    // [ -2, -1, 0, 1, 2 ]
    
    console.log (reduce (add) (0) ([1,2,3,4]))
    // 10
    
    console.log (map (sq) ([1,2,3,4]))
    // [ 1, 4, 9, 16 ]

    /* const U = f => f (f)
     *
     * const Y = U (h => f => f (x => U (h) (f) (x)))
     *
     * const fibonacci = Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1)
     *
     */
    
    /*
     * given fibonacci (7)
     *
     * replace fibonacci with its definition
     * Y (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
     *
     * replace Y with its definition
     * U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
    //
     * replace U with its definition
     * (f => f (f)) U (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
     */
    
    let result =
      (f => f (f)) (h => f => f (x => U (h) (f) (x))) (f => a => b => x => x === 0 ? a : f (b) (a + b) (x - 1)) (0) (1) (7)
      
    console.log (result) // 13

        4
  •  13
  •   bobince    14 年前

    arguments.callee

    (function foo(data){
        data++;
        var nothing = function() {
            foo(data);
        }
        nothing();
    })();
    

    foo

    nothing

        5
  •  12
  •   svidgen    11 年前

    ({
      do: function() {
        console.log("don't run this ...");
        this.do();
      }
    }).do();
    

        6
  •  11
  •   fcalderan    14 年前
    (function(data){
        var recursive = arguments.callee;
        data = data+1;
        var nothing = function() {
            recursive(data)
        }
        nothing();
    })();
    
        7
  •  6
  •   ArtBIT    14 年前

    (foo = function() { foo(); })()
    

    (recur = function(data){
        data = data+1;
        var nothing = function() {
            if (data > 100) return; // put recursion limit
            recur(data);
        }
        nothing();
    })(/* put data init value here */ 0);
    
        8
  •  3
  •   xj9    14 年前

    (function () {
        // Pass
    }());
    

    (function foo () {
        foo();
    }());
    foo //-> undefined
    
        9
  •  3
  •   Riccardo Bassilichi    11 年前

        var functionCaller = function(thisCaller, data) {
            data = data + 1;
            var nothing = function() {
                thisCaller(thisCaller, data);
            };
            nothing();
        };
        functionCaller(functionCaller, data);
    
        10
  •  3
  •   user6445533    8 年前

    map

    const map = f => acc => ([head, ...tail]) => head === undefined 
     ? acc
     : map (f) ([...acc, f(head)]) (tail);
    
    const sqr = x => x * x;
    const xs = [1,2,3,4,5];
    
    console.log(map(sqr) ([0]) (xs)); // [0] modifies the structure of the array

    acc 到另一个函数中,例如:

    const map = f => xs => {
      let next = acc => ([head, ...tail]) => head === undefined
       ? acc
       : map ([...acc, f(head)]) (tail);
    
      return next([])(xs);
    }
    

    但这个解决方案相当冗长。让我们用被低估的 U 组合器:

    const U = f => f(f);
    
    const map = f => U(h => acc => ([head, ...tail]) => head === undefined 
     ? acc
     : h(h)([...acc, f(head)])(tail))([]);
    
    const sqr = x => x * x;
    const xs = [1,2,3,4,5];
    
    console.log(map(sqr) (xs));

    简明扼要,不是吗? U 非常简单,但缺点是递归调用有点模糊: sum(...) 变成 h(h)(...) -仅此而已。

        11
  •  2
  •   Nitij    10 年前

    我不确定是否仍然需要答案,但也可以使用使用function.bind创建的委托来完成此操作:

        var x = ((function () {
            return this.bind(this, arguments[0])();
        }).bind(function (n) {
            if (n != 1) {
                return n * this.bind(this, (n - 1))();
            }
            else {
                return 1;
            }
        }))(5);
    
        console.log(x);
    

    这不涉及命名函数或arguments.callee。

        12
  •  1
  •   Peter Ajtai    14 年前

    就像波宾斯写的,简单地说出你的函数。

    但是,我猜您也希望传递一个初始值,并最终停止您的函数!

    var initialValue = ...
    
    (function recurse(data){
        data++;
        var nothing = function() {
            recurse(data);
        }
        if ( ... stop condition ... )
            { ... display result, etc. ... }
        else
            nothing();
    }(initialValue));
    

    working jsFiddle example (uses data += data for fun)


        13
  •  1
  •   radio_babylon    9 年前

    我需要(或者更确切地说,需要)一个单行匿名函数沿着一个构建字符串的对象走,并像这样处理它:

    var cmTitle = 'Root' + (function cmCatRecurse(cmCat){return (cmCat == root) ? '' : cmCatRecurse(cmCat.parent) + ' : ' + cmCat.getDisplayName();})(cmCurrentCat);
    

    它生成一个字符串,如“root:foo:bar:baz:…”

        14
  •  1
  •   user6445533    8 年前

    使用ES2015,我们可以稍微使用语法,滥用默认参数和thunk。后者只是没有任何参数的函数:

    const applyT = thunk => thunk();
    
    const fib = n => applyT(
      (f = (x, y, n) => n === 0 ? x : f(y, x + y, n - 1)) => f(0, 1, n)
    );
    
    console.log(fib(10)); // 55
    
    // Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55...

    请注意 f (x, y, n) => n === 0 ? x : f(y, x + y, n - 1) applyT

        15
  •  0
  •   jforjs    10 年前

    var sum = (function(foo,n){
      return n + foo(foo,n-1);
    })(function(foo,n){
         if(n>1){
             return n + foo(foo,n-1)
         }else{
             return n;
         }
    },5); //function takes two argument one is function and another is 5
    
    console.log(sum) //output : 15
    
        16
  •  0
  •   englebart    9 年前

    // function takes two argument: first is recursive function and second is input
    var sum = (function(capturedRecurser,n){
      return capturedRecurser(capturedRecurser, n);
    })(function(thisFunction,n){
         if(n>1){
             return n + thisFunction(thisFunction,n-1)
         }else{
             return n;
         }
    },5); 
    
    console.log(sum) //output : 15
    

        17
  •  0
  •   Ricardo Freitas    8 年前

    U Y

    const U = f => f(f) U(selfFn => arg => selfFn(selfFn)('to infinity and beyond'))

    const Y = gen => U(f => gen((...args) => f(f)(...args))) Y(selfFn => arg => selfFn('to infinity and beyond'))

        18
  •  0
  •   myfirstAnswer    6 年前

    rosetta-code

    var Y = f => (x => x(x))(y => f(x => y(y)(x)));
    
        19
  •  -1
  •   Dan Jones    9 年前

    arguments.callee

    var fac = function(x) { 
        if (x == 1) return x;
        else return x * arguments.callee(x-1);
    }