Nie twierdzę, że w ogóle to rozumiem, ale jeśli to komuś pomaga ...
Rozważ definicję fix
. fix f = let x = f x in x
. Zadziwiająca część x
jest zdefiniowana jako f x
. Ale pomyśl o tym przez chwilę.
x = f x
Ponieważ x = fx, możemy podstawić wartość x
po prawej stronie tego, prawda? Więc dlatego...
x = f . f $ x
x = f . f . f $ x
x = f . f . f . f . f . f . f . f . f . f . f $ x
Tak więc sztuczka polega na tym, że aby zakończyć, f
trzeba wygenerować jakąś strukturę, tak aby późniejszy f
wzorzec mógł dopasować tę strukturę i zakończyć rekursję, bez faktycznego dbania o pełną "wartość" swojego parametru (?)
Chyba że, oczywiście, chcesz zrobić coś takiego, jak stworzenie nieskończonej listy, jak zilustrowano luqui.
Silnia wyjaśnienia TomMD jest dobra. Podpis typu poprawki to (a -> a) -> a
. Innymi słowy, typ podpisu dla (\recurse d -> if d > 0 then d * (recurse (d-1)) else 1)
to . Więc możemy tak powiedzieć . W ten sposób fix przyjmuje naszą funkcję, która jest lub naprawdę, i zwróci wynik typu , innymi słowy, inną funkcję!(b -> b) -> b -> b
(b -> b) -> (b -> b)
a = (b -> b)
a -> a
(b -> b) -> (b -> b)
a
b -> b
Czekaj, myślałem, że powinien zwrócić stały punkt ... a nie funkcję. Cóż, w pewnym sensie (ponieważ funkcje to dane). Możesz sobie wyobrazić, że dało nam to ostateczną funkcję znajdowania silni. Daliśmy mu funkcję, która nie wiedziała, jak się powtarzać (stąd jeden z jej parametrów jest funkcją używaną do rekurencji), i fix
nauczyliśmy ją, jak się powtarzać.
Pamiętasz, jak powiedziałem, że f
musi wygenerować jakąś strukturę, aby później f
można było dopasować wzorzec i zakończyć? Cóż, to chyba nie do końca w porządku. TomMD zilustrował, jak możemy rozszerzyć, x
aby zastosować funkcję i przejść do przypadku podstawowego. Do swojej funkcji użył warunku if / then i to właśnie powoduje zakończenie. Po wielokrotnych zamianach in
część całej definicji fix
ostatecznie przestaje być definiowana w kategoriach x
i wtedy jest obliczalna i kompletna.
fix error
ghci i poczuć się dobrze ze sobą”.