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

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

    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
    

提交回复
热议问题