Funkcje takie jak ten są często spotykanych w kombinatorów stałoprzecinkowych. na przykład jedna forma z Y combinator jest napisana λf.(λx.f (x x)) (λx.f (x x))
. Kombinatory o ustalonym punkcie są używane do implementacji ogólnej rekursji w nietypowym rachunku lambda bez żadnych dodatkowych konstruktów rekursywnych, i jest to część tego, co tworzy niezaszyfrowany rachunek lambda Turing-complete.
Kiedy ludzie opracowali simply-typed lambda calculus, który jest naiwnym statycznym systemem typu na szczycie rachunku lambda, odkryli, że nie można już pisać takich funkcji. W rzeczywistości nie można wykonać ogólnej rekursji w prostym typie rachunku lambda; dlatego też prosty rachunek lambda nie jest już Turing-complete. (Interesującym efektem ubocznym jest to, że programy po prostu wpisany lambda rachunku zawsze zakończyć.)
rzeczywistym statycznie wpisywanych języków programowania, takich jak konieczność Standardowy ML wbudowanym mechanizmom rekurencyjnych w celu przezwyciężenia tego problemu, takie jak nazwy funkcji rekurencyjnych (zdefiniowane jako val rec
lub fun
) i nazwane rekursywnymi typami danych.
Nadal można używać rekurencyjnych typów danych do symulacji czegoś, co się chce, ale nie jest tak piękne.
Zasadniczo chcesz zdefiniować typ, taki jak 'a foo = 'a foo -> 'a
; jest to jednak niedozwolone. Zamiast tego zawinąć go w typ danych: datatype 'a foo = Wrap of ('a foo -> 'a);
datatype 'a foo = Wrap of ('a foo -> 'a);
fun unwrap (Wrap x) = x;
Zasadniczo Wrap
i unwrap
są wykorzystywane do transformacji między 'a foo
i 'a foo -> 'a
, i vice versa.
Kiedy trzeba wywołać funkcję na sobie, zamiast x x
, musisz jawnie napisać (unwrap x) x
(lub unwrap x x
); tj. unwrap
przekształca go w funkcję, którą można następnie zastosować do pierwotnej wartości.
P.S. Inny język ML, OCaml, ma opcję włączania typów rekurencyjnych (zwykle wyłączone); jeśli uruchamiasz interpreter lub kompilator z flagą -rectypes
, możliwe jest pisanie takich rzeczy, jak fun x -> x x
. Zasadniczo, za kulisami, sprawdzanie typu określa miejsca, w których należy "zawinąć" i "rozwinąć" typ rekursywny, a następnie wstawia je dla ciebie. Nie jestem świadomy żadnej standardowej implementacji ML, która ma podobne funkcje typów rekursywnych.
Jeśli ktoś jest zainteresowany, odkryłem, że jest to nazywane [U Combinator (patrz na dole strony)] (http://www.ucombinator.org/), ale nie można znaleźć o wiele więcej. –
Nie wiedziałem, że to się nazywa kombinator U, ale jak podaje ta strona, jest on używany do budowania (najwyraźniej najkrótszego) nie kończącego się programu beztypowego rachunku lambda, który umieściłem w odpowiedzi. –