Which languages support *recursive* function literals / anonymous functions?

后端 未结 16 2136
一整个雨季
一整个雨季 2021-02-04 05:09

It seems quite a few mainstream languages support function literals these days. They are also called anonymous functions, but I don\'t care if they have a name. The important th

相关标签:
16条回答
  • 2021-02-04 05:54

    It also seems Mathematica lets you define recursive functions using #0 to denote the function itself, as:

    (expression[#0]) &
    

    e.g. a factorial:

    fac = Piecewise[{{1, #1 == 0}, {#1 * #0[#1 - 1], True}}] &;
    

    This is in keeping with the notation #i to refer to the ith parameter, and the shell-scripting convention that a script is its own 0th parameter.

    0 讨论(0)
  • 2021-02-04 05:55

    Because I was curious, I actually tried to come up with a way to do this in MATLAB. It can be done, but it looks a little Rube-Goldberg-esque:

    >> fact = @(val,branchFcns) val*branchFcns{(val <= 1)+1}(val-1,branchFcns);
    >> returnOne = @(val,branchFcns) 1;
    >> branchFcns = {fact returnOne};
    >> fact(4,branchFcns)
    
    ans =
    
        24
    
    >> fact(5,branchFcns)
    
    ans =
    
       120
    
    0 讨论(0)
  • 2021-02-04 05:56

    Most languages support it through use of the Y combinator. Here's an example in Python (from the cookbook):

    # Define Y combinator...come on Gudio, put it in functools!
    Y = lambda g: (lambda f: g(lambda arg: f(f)(arg))) (lambda f: g(lambda arg: f(f)(arg)))
    
    # Define anonymous recursive factorial function
    fac = Y(lambda f: lambda n: (1 if n<2 else n*f(n-1)))
    assert fac(7) == 5040
    
    0 讨论(0)
  • 2021-02-04 05:57

    In C# you need to declare a variable to hold the delegate, and assign null to it to make sure it's definitely assigned, then you can call it from within a lambda expression which you assign to it:

    Func<int, int> fac = null;
    fac = n => n < 2 ? 1 : n * fac(n-1);
    Console.WriteLine(fac(7));
    

    I think I heard rumours that the C# team was considering changing the rules on definite assignment to make the separate declaration/initialization unnecessary, but I wouldn't swear to it.

    One important question for each of these languages / runtime environments is whether they support tail calls. In C#, as far as I'm aware the MS compiler doesn't use the tail. IL opcode, but the JIT may optimise it anyway, in certain circumstances. Obviously this can very easily make the difference between a working program and stack overflow. (It would be nice to have more control over this and/or guarantees about when it will occur. Otherwise a program which works on one machine may fail on another in a hard-to-fathom manner.)

    Edit: as FryHard pointed out, this is only pseudo-recursion. Simple enough to get the job done, but the Y-combinator is a purer approach. There's one other caveat with the code I posted above: if you change the value of fac, anything which tries to use the old value will start to fail, because the lambda expression has captured the fac variable itself. (Which it has to in order to work properly at all, of course...)

    0 讨论(0)
  • 2021-02-04 05:57

    Clojure can do it, as fn takes an optional name specifically for this purpose (the name doesn't escape the definition scope):

    > (def fac (fn self [n] (if (< n 2) 1 (* n (self (dec n))))))
    #'sandbox17083/fac
    > (fac 5)
    120
    > self
    java.lang.RuntimeException: Unable to resolve symbol: self in this context
    

    If it happens to be tail recursion, then recur is a much more efficient method:

    > (def fac (fn [n] (loop [count n result 1]
                         (if (zero? count)
                           result
                           (recur (dec count) (* result count))))))
    
    0 讨论(0)
  • 2021-02-04 05:58

    You've mixed up some terminology here, function literals don't have to be anonymous.

    In javascript the difference depends on whether the function is written as a statement or an expression. There's some discussion about the distinction in the answers to this question.

    Lets say you are passing your example to a function:

    foo(function(n){if (n<2) {return 1;} else {return n * arguments.callee(n-1);}});
    

    This could also be written:

    foo(function fac(n){if (n<2) {return 1;} else {return n * fac(n-1);}});
    

    In both cases it's a function literal. But note that in the second example the name is not added to the surrounding scope - which can be confusing. But this isn't widely used as some javascript implementations don't support this or have a buggy implementation. I've also read that it's slower.

    Anonymous recursion is something different again, it's when a function recurses without having a reference to itself, the Y Combinator has already been mentioned. In most languages, it isn't necessary as better methods are available. Here's a link to a javascript implementation.

    0 讨论(0)
提交回复
热议问题