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

后端 未结 16 2096
一整个雨季
一整个雨季 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:46

    C#

    Reading Wes Dyer's blog, you will see that @Jon Skeet's answer is not totally correct. I am no genius on languages but there is a difference between a recursive anonymous function and the "fib function really just invokes the delegate that the local variable fib references" to quote from the blog.

    The actual C# answer would look something like this:

    delegate Func<A, R> Recursive<A, R>(Recursive<A, R> r);
    
    static Func<A, R> Y<A, R>(Func<Func<A, R>, Func<A, R>> f)
    {
        Recursive<A, R> rec = r => a => f(r(r))(a);
        return rec(rec);
    }
    
    static void Main(string[] args)
    {
        Func<int,int> fib = Y<int,int>(f => n => n > 1 ? f(n - 1) + f(n - 2) : n);
        Func<int, int> fact = Y<int, int>(f => n => n > 1 ? n * f(n - 1) : 1);
        Console.WriteLine(fib(6));                          // displays 8
        Console.WriteLine(fact(6));
        Console.ReadLine();
    } 
    
    0 讨论(0)
  • 2021-02-04 05:47

    In Perl 6:

    my $f = -> $n { if ($n <= 1) {1} else {$n * &?BLOCK($n - 1)} }
    $f(42);  # ==> 1405006117752879898543142606244511569936384000000000
    
    0 讨论(0)
  • 2021-02-04 05:48

    You can do it in Perl:

    my $factorial = do {
      my $fac;
      $fac = sub {
        my $n = shift;
        if ($n < 2) { 1 } else { $n * $fac->($n-1) }
      };
    };
    
    print $factorial->(4);
    

    The do block isn't strictly necessary; I included it to emphasize that the result is a true anonymous function.

    0 讨论(0)
  • You can do this in Matlab using an anonymous function which uses the dbstack() introspection to get the function literal of itself and then evaluating it. (I admit this is cheating because dbstack should probably be considered extralinguistic, but it is available in all Matlabs.)

    f = @(x) ~x || feval(str2func(getfield(dbstack, 'name')), x-1)
    

    This is an anonymous function that counts down from x and then returns 1. It's not very useful because Matlab lacks the ?: operator and disallows if-blocks inside anonymous functions, so it's hard to construct the base case/recursive step form.

    You can demonstrate that it is recursive by calling f(-1); it will count down to infinity and eventually throw a max recursion error.

    >> f(-1)
    ??? Maximum recursion limit of 500 reached. Use set(0,'RecursionLimit',N)
    to change the limit.  Be aware that exceeding your available stack space can
    crash MATLAB and/or your computer.
    

    And you can invoke the anonymous function directly, without binding it to any variable, by passing it directly to feval.

    >> feval(@(x) ~x || feval(str2func(getfield(dbstack, 'name')), x-1), -1)
    ??? Maximum recursion limit of 500 reached. Use set(0,'RecursionLimit',N)
    to change the limit.  Be aware that exceeding your available stack space can
    crash MATLAB and/or your computer.
    
    Error in ==> create@(x)~x||feval(str2func(getfield(dbstack,'name')),x-1)
    

    To make something useful out of it, you can create a separate function which implements the recursive step logic, using "if" to protect the recursive case against evaluation.

    function out = basecase_or_feval(cond, baseval, fcn, args, accumfcn)
    %BASECASE_OR_FEVAL Return base case value, or evaluate next step
    if cond
        out = baseval;
    else
        out = feval(accumfcn, feval(fcn, args{:}));
    end
    

    Given that, here's factorial.

    recursive_factorial = @(x) basecase_or_feval(x < 2,...
        1,...
        str2func(getfield(dbstack, 'name')),...
        {x-1},...
        @(z)x*z);
    

    And you can call it without binding.

    >> feval( @(x) basecase_or_feval(x < 2, 1, str2func(getfield(dbstack, 'name')), {x-1}, @(z)x*z), 5)
    ans =
       120
    
    0 讨论(0)
  • 2021-02-04 05:53

    Well, apart from Common Lisp (labels) and Scheme (letrec) which you've already mentioned, JavaScript also allows you to name an anonymous function:

    var foo = {"bar": function baz() {return baz() + 1;}};
    

    which can be handier than using callee. (This is different from function in top-level; the latter would cause the name to appear in global scope too, whereas in the former case, the name appears only in the scope of the function itself.)

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

    F# has "let rec"

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