Saya sudah belajar F # dan itu mulai mempengaruhi bagaimana saya berpikir ketika saya pemrograman C #. Untuk itu, saya telah menggunakan rekursi ketika saya merasa hasilnya meningkatkan keterbacaan dan saya tidak bisa membayangkan itu berakhir pada stack overflow.
Hal ini membuat saya bertanya apakah kompiler dapat secara otomatis mengonversi fungsi rekursif ke bentuk non-rekursif yang setara?
programming-languages
compiler
recursion
Aaron Anodide
sumber
sumber
return recursecall(args);
rekursi, hal-hal yang lebih kompleks dimungkinkan dengan membuat tumpukan eksplisit dan memutarnya, tetapi saya ragu mereka akanJawaban:
Ya, beberapa bahasa dan pelengkap akan mengubah logika rekursif ke logika non-rekursif. Ini dikenal sebagai pengoptimalan panggilan ekor - perhatikan bahwa tidak semua panggilan rekursif dapat dioptimalkan panggilan ekor. Dalam situasi ini, kompiler mengenali fungsi dari form:
Di sini, bahasa dapat mengenali bahwa hasil yang dikembalikan adalah hasil dari fungsi lain dan mengubah panggilan fungsi dengan bingkai tumpukan baru menjadi lompatan.
Sadarilah bahwa metode faktorial klasik:
adalah tidak ekor panggilan optimizatable karena pemeriksaan yang diperlukan pada kembali.
Untuk membuat panggilan ekor ini dapat dioptimalkan,
Kompilasi kode ini dengan
gcc -O2 -S fact.c
(-O2 diperlukan untuk mengaktifkan optimisasi dalam kompiler, tetapi dengan lebih banyak optimasi dari -O3 semakin sulit bagi manusia untuk membaca ...)Satu dapat melihat di segmen
.L4
,jne
daripadacall
(yang melakukan panggilan subrutin dengan bingkai tumpukan baru).Harap perhatikan bahwa ini dilakukan dengan C. Optimasi panggilan ekor di java sulit dan tergantung pada implementasi JVM - pengulangan ekor + java dan pengoptimalan pengulangan ekor + pengoptimalan adalah set tag yang baik untuk dijelajahi. Anda mungkin menemukan bahasa JVM lainnya dapat mengoptimalkan rekursi ekor lebih baik (coba clojure (yang membutuhkan pengulangan untuk mengoptimalkan panggilan bolak-balik ), atau scala).
sumber
Tapak dengan hati-hati.
Jawabannya adalah ya, tetapi tidak selalu, dan tidak semuanya. Ini adalah teknik yang menggunakan beberapa nama berbeda, tetapi Anda dapat menemukan beberapa informasi yang cukup definitif di sini dan di wikipedia .
Saya lebih suka nama "Tail Call Optimization" tetapi ada orang lain dan beberapa orang akan membingungkan istilah itu.
Yang mengatakan ada beberapa hal penting untuk disadari:
Untuk mengoptimalkan panggilan ekor, panggilan ekor memerlukan parameter yang diketahui pada saat panggilan dilakukan. Itu berarti jika salah satu parameter adalah panggilan ke fungsi itu sendiri, maka itu tidak dapat dikonversi menjadi loop, karena ini akan memerlukan bersarang sembarang dari loop yang tidak dapat diperluas pada waktu kompilasi.
C # tidak andal mengoptimalkan panggilan ekor. IL memiliki instruksi untuk melakukannya sehingga kompiler F # akan memancarkan, tetapi kompiler C # akan memancarkannya secara tidak konsisten, dan tergantung pada situasi JIT, JIT mungkin atau mungkin tidak melakukannya sama sekali. Semua indikasi adalah Anda tidak boleh bergantung pada panggilan ekor Anda yang dioptimalkan dalam C #, risiko meluap dalam melakukannya adalah signifikan dan nyata
sumber