Czy można mieć funkcję PHP zarówno rekurencyjną, jak i anonimową? To jest moja próba uruchomienia go, ale nie przechodzi w nazwie funkcji.
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Wiem też, że to zły sposób na wdrożenie silni, to tylko przykład.
global $factorial
?print $factorial( 0);
Odpowiedzi:
Aby to zadziałało, musisz przekazać $ silnia jako odniesienie
źródło
&
jest wartościowe. Wszystko z tym&
jest przez odniesienie. „Obiekty” nie są wartościami w PHP5 i nie można ich przypisywać ani przekazywać. Masz do czynienia ze zmienną, której wartość jest odwołaniem do obiektu. Jak wszystkie zmienne, może być przechwycony przez wartość lub przez odniesienie, w zależności od tego, czy istnieje&
.$factorial
zostaną zmienione przed wywołaniem funkcji i może to spowodować dziwne zachowanie.Wiem, że to może nie być proste podejście, ale dowiedziałem się o technice zwanej „poprawką” z języków funkcjonalnych.
fix
Funkcję z Haskell jest znany ogólnie jako combinator Y , który jest jednym z najbardziej znanych złożone jest ze stałą .Punkt stały jest wartością niezmienioną przez funkcję: punktem stałym funkcji f jest dowolny x taki, że x = f (x). Kombinator punktu stałego y jest funkcją, która zwraca punkt stały dla dowolnej funkcji f. Ponieważ y (f) jest stałym punktem f, mamy y (f) = f (y (f)).
Zasadniczo kombinator Y tworzy nową funkcję, która przyjmuje wszystkie argumenty oryginału, plus dodatkowy argument, który jest funkcją rekurencyjną. Jak to działa, jest bardziej oczywiste, używając notacji curry. Zamiast pisać argumenty w nawiasach (
f(x,y,...)
), napisać je po funkcji:f x y ...
. Kombinator Y jest zdefiniowany jakoY f = f (Y f)
; lub z jednego argumentu funkcji recursed,Y f x = f (Y f) x
.Ponieważ PHP nie działa automatycznie curry funkcji, jest trochę hack do
fix
pracy, ale myślę, że to interesujące.Pamiętaj, że jest to prawie to samo, co proste rozwiązania zamykające, które opublikowali inni, ale funkcja
fix
tworzy zamknięcie dla Ciebie. Kombinatory stałoprzecinkowe są nieco bardziej złożone niż użycie zamknięcia, ale są bardziej ogólne i mają inne zastosowania. Chociaż metoda zamknięcia jest bardziej odpowiednia dla PHP (który nie jest strasznie funkcjonalnym językiem), pierwotny problem jest bardziej ćwiczeniem niż produkcją, więc kombinator Y jest realnym podejściem.źródło
call_user_func_array()
jest wolny jak Boże Narodzenie.call_user_func_array
.array_unshift( $args, fix($func) );
? Argumenty są już obciążone parametrami, a faktyczna rekurencja jest wykonywana przez call_user_func_array (), więc co robi ta linia?Chociaż nie jest to do użytku praktycznego, rozszerzenie mpyw-junks / phpext-callee na poziomie C zapewnia anonimową rekurencję bez przypisywania zmiennych .
źródło
W nowszych wersjach PHP możesz to zrobić:
Może to potencjalnie prowadzić do dziwnych zachowań.
źródło
Możesz używać Y Combinator w PHP 7.1+ jak poniżej:
Graj z nim: https://3v4l.org/7AUn2
Kody źródłowe z: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php
źródło
Z anonimową klasą (PHP 7+), bez definiowania zmiennej:
źródło