Apakah mungkin untuk memiliki fungsi PHP yang bersifat rekursif dan anonim? Ini adalah upaya saya untuk membuatnya berfungsi, tetapi tidak lulus dalam nama fungsi.
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
Saya juga sadar bahwa ini adalah cara yang buruk untuk menerapkan faktorial, itu hanya sebuah contoh.
global $factorial
?print $factorial( 0);
Jawaban:
Agar itu berfungsi, Anda harus memberikan $ factorial sebagai referensi
sumber
&
nilai. Semuanya dengan&
referensi. "Objek" bukan nilai dalam PHP5 dan tidak dapat ditetapkan atau diteruskan. Anda berhadapan dengan variabel yang nilainya adalah referensi objek. Seperti semua variabel, ini dapat ditangkap dengan nilai atau referensi, tergantung pada apakah ada&
.$factorial
akan diubah sebelum fungsi dipanggil dan itu mungkin terjadi dengan perilaku aneh.Saya tahu ini mungkin bukan pendekatan yang sederhana, tetapi saya belajar tentang teknik yang disebut "memperbaiki" dari bahasa fungsional. The
fix
Fungsi dari Haskell dikenal lebih umum sebagai combinator Y , yang merupakan salah satu yang paling terkenal combinators titik tetap .Titik tetap adalah nilai yang tidak diubah oleh suatu fungsi: titik tetap dari fungsi f adalah x sehingga x = f (x). Sebuah titik tetap combinator y adalah fungsi yang mengembalikan titik tetap untuk setiap fungsi f. Karena y (f) adalah titik tetap dari f, kita memiliki y (f) = f (y (f)).
Pada dasarnya, kombinator Y menciptakan fungsi baru yang mengambil semua argumen dari yang asli, ditambah argumen tambahan yang merupakan fungsi rekursif. Cara kerjanya lebih jelas menggunakan notasi curried. Alih-alih menulis argumen dalam kurung (
f(x,y,...)
), menulis mereka setelah fungsi:f x y ...
. Combinator Y didefinisikan sebagaiY f = f (Y f)
; atau, dengan argumen tunggal untuk fungsi berulangY f x = f (Y f) x
,.Karena PHP tidak secara otomatis menjelajah fungsi, ini sedikit hack untuk membuat
fix
pekerjaan, tapi saya pikir ini menarik.Perhatikan bahwa ini hampir sama dengan solusi penutupan sederhana yang diposkan orang lain, tetapi fungsinya
fix
menciptakan penutupan untuk Anda. Combinator titik tetap sedikit lebih kompleks daripada menggunakan penutup, tetapi lebih umum, dan memiliki kegunaan lain. Sementara metode penutupan lebih cocok untuk PHP (yang bukan bahasa yang sangat fungsional), masalah asli lebih merupakan latihan daripada untuk produksi, sehingga kombinator Y adalah pendekatan yang layak.sumber
call_user_func_array()
ini lambat seperti Natal.call_user_func_array
.array_unshift( $args, fix($func) );
? Args sudah sarat dengan parameter, dan rekursi aktual dilakukan oleh call_user_func_array (), jadi apa yang dilakukan baris itu?Meskipun bukan untuk penggunaan praktis, ekstensi tingkat-C mpyw-junk / phpext-callee menyediakan rekursi anonim tanpa menetapkan variabel .
sumber
Di versi PHP yang lebih baru Anda dapat melakukan ini:
Ini berpotensi menyebabkan perilaku aneh.
sumber
Anda dapat menggunakan Y Combinator di PHP 7.1+ seperti di bawah ini:
Mainkan dengannya: https://3v4l.org/7AUn2
Kode sumber dari: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php
sumber
Dengan kelas anonim (PHP 7+), tanpa mendefinisikan variabel:
sumber