Какие языки поддерживают * рекурсивные * функциональные литералы / анонимные функции? - PullRequest
16 голосов
/ 01 октября 2008

Кажется, что в настоящее время довольно много основных языков поддерживают функциональные литералы . Их также называют анонимными функциями , но мне все равно, есть ли у них имя. Важно то, что литерал функции - это выражение, которое дает функцию, которая еще не была определена где-либо еще, поэтому, например, в C &printf не считается.

ИЗМЕНИТЬ, чтобы добавить: если у вас есть подлинное буквальное выражение функции <exp>, вы должны быть в состоянии передать его функции f(<exp>) или сразу применить его к аргументу, т.е. <exp>(5).

Мне любопытно, на каких языках можно писать функциональные литералы, которые рекурсивны . Статья Википедии " анонимная рекурсия " не содержит примеров программирования.

Давайте использовать рекурсивную факториальную функцию в качестве примера.

Вот те, кого я знаю:

  • JavaScript / ECMAScript может сделать это с callee:

    function(n){if (n<2) {return 1;} else {return n * arguments.callee(n-1);}}
    
  • это просто на языках с letrec, например, Haskell (который называет его let):

    let fac x = if x<2 then 1 else fac (x-1) * x in fac

    и есть эквиваленты в Лиспе и Схеме. Обратите внимание, что привязка fac является локальной для выражения, поэтому все выражение фактически является анонимной функцией.

Есть ли другие?

Ответы [ 16 ]

0 голосов
/ 17 января 2017

Clojure может сделать это, поскольку fn принимает необязательное имя специально для этой цели (имя не выходит за рамки определения):

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

Если это хвостовая рекурсия, то recur - гораздо более эффективный метод:

> (def fac (fn [n] (loop [count n result 1]
                     (if (zero? count)
                       result
                       (recur (dec count) (* result count))))))
0 голосов
/ 20 мая 2010

'Таким образом, вы неправильно поняли анонимные функции, речь идет не только о создании во время выполнения, но и о области действия. Рассмотрим этот макрос схемы:

(define-syntax lambdarec
  (syntax-rules ()
    ((lambdarec (tag . params) . body)
     ((lambda ()
       (define (tag . params) . body)
        tag)))))

такой, что:

(lambdarec (f n) (if (<= n 0) 1 (* n (f (- n 1)))))

Оценивает истинную анонимную рекурсивную факториальную функцию, которую можно использовать, например:

(let ;no letrec used
    ((factorial (lambdarec (f n) (if (<= n 0) 1 (* n (f (- n 1)))))))
  (factorial 4)) ; ===> 24

Однако истинная причина анонимности заключается в том, что если я это сделаю:

((lambdarec (f n) (if (<= n 0) 1 (* n (f (- n 1))))) 4)

Функция впоследствии очищается из памяти и не имеет области видимости, поэтому после этого:

(f 4)

Будет либо сигнализировать об ошибке, либо будет привязан к тому, с чем f был связан ранее.

В Хаскеле, специальный способ достичь этого будет:

\n -> let fac x = if x<2 then 1 else fac (x-1) * x
    in fac n

Разница в том, что эта функция не имеет области видимости, если я ее не использую, а для Haskell значение Lazy - то же самое, что и пустая строка кода, оно действительно буквально, поскольку имеет тот же эффект, что и Код C:

3;

Буквальное число. И даже если я воспользуюсь им сразу после этого, он исчезнет. В этом смысл буквальных функций, а не создание во время выполнения как таковое.

0 голосов
/ 18 мая 2010

Анонимные функции существуют в C ++ 0x с лямбдами, и они могут быть рекурсивными, хотя я не уверен насчет анонимности.

auto kek = [](){kek();}
0 голосов
/ 13 марта 2009

Поскольку мне было любопытно, я действительно пытался придумать способ сделать это в MATLAB . Это можно сделать, но выглядит немного по-рубе-голдбергски:

>> 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 голосов
/ 01 октября 2008

Delphi включает анонимные функции с версией 2009.

Пример из http://blogs.codegear.com/davidi/2008/07/23/38915/

type
  // method reference
  TProc = reference to procedure(x: Integer);               

procedure Call(const proc: TProc);
begin
  proc(42);
end;

Использование:

var
  proc: TProc;
begin
  // anonymous method
  proc := procedure(a: Integer)
  begin
    Writeln(a);
  end;               

  Call(proc);
  readln
end.
0 голосов
/ 01 октября 2008

Я думаю, что это может быть не совсем то, что вы ищете, но в Лиспе «метки» могут использоваться для динамического объявления функций, которые можно вызывать рекурсивно.

(labels ((factorial (x) ;define name and params
    ; body of function addrec
    (if (= x 1)
      (return 1)
      (+ (factorial (- x 1))))) ;should not close out labels
  ;call factorial inside labels function
  (factorial 5)) ;this would return 15 from labels
...