Saya sedang mengerjakan bahasa pemrograman kecil saya sendiri untuk tujuan pendidikan, dan saya mengalami sedikit masalah. Ada beberapa solusi berbeda untuk itu, tetapi semuanya tampaknya tidak sempurna - dan dari apa yang saya pahami, tidak perlu. Tetapi membaca buku-buku yang saya miliki dan pencarian google, saya tidak dapat menemukan solusi yang elegan.
Jadi, masalahnya adalah bahwa saya membangun kalkulus lambda dasar seperti yang saya mengerti. Saya telah mendefinisikan benar / salah sebagai istilah abstraksi. Saya dapat menggabungkan ini dengan fungsi yang harus dilakukan jika / maka / selain itu semacam perilaku. Masalahnya muncul dengan loop. Saya bisa mendefinisikan loop sementara dasar melalui rekursi, tetapi dalam praktiknya, itu menyebabkan stack overflow. Seperti yang saya pahami, solusi yang biasa dilakukan adalah dengan melakukan Tail Call Optimization, tetapi saya tidak melihat bagaimana saya bisa - kondisional didefinisikan dalam bahasa. Karena itu, kompiler tidak tahu bahwa tubuh loop sementara berada di posisi ekor.
Buku naga berfokus pada penerapan loop dengan asumsi ada label dan foto. Saya pasti bisa melakukan itu. Tampaknya seolah-olah bahasa lain yang tidak membangun dalam konstruksi perulangan setidaknya membangun dalam kondisi dan kemudian melakukan TCO. Dan saya pasti bisa melakukannya juga. Tetapi pemahaman saya adalah bahwa selama saya dapat menerapkan abstraksi dan melakukan reduksi, maka loop (dan yang lainnya) harus dapat dibangun dari blok dasar tersebut.
Jadi apa yang saya lewatkan? Atau apakah ini salah satu kasus di mana "Anda dapat memodelkan apa pun setelah Anda memiliki X dan Y" tidak sama dengan "Anda dapat memodelkan apa pun setelah Anda memiliki X dan Y di komputer nyata" dan built-in diperlukan untuk praktis tujuan?
sumber
Jawaban:
Jadi saya berhasil menyelesaikan masalah ini hari ini. Kode untuk loop sementara saya:
Ketika saya pergi untuk membangun ini ke CIL (runtime berbasis stack, penting untuk psuedocode, tidak penting untuk jawabannya) sepertinya:
Yang penting saya hilang adalah bahwa dalam
while
kode, kondisional adalah hal di posisi ekor. Dari perspektif kompiler, fungsi blok dan sementara adalah dua fungsi terpisah, dengan dua "ekor" terpisah. Masing-masing mudah dievaluasi untuk posisi ekor, membuat optimisasi layak meskipun kurangnya persyaratan bawaan.sumber
Saya pikir Anda kehilangan gagasan kelanjutan . Meskipun kompiler Anda mungkin tidak mengandalkan gagasan itu, sebagai perancang kompiler dengan bahasa fungsional sebagai bahasa sumber atau menengah (atau target), penting untuk memahami gagasan itu dan mengingatnya.
Kelanjutan sepotong kode menjelaskan apa yang keluar dari kode. Dalam istilah imperatif, ini tidak hanya mencakup lokasi tempat kode melompat atau jatuh, tetapi juga status program (tumpukan dan tumpukan) pada saat itu. Dalam istilah kalkulus lambda, kelanjutan subterm adalah konteks di mana ia dievaluasi.
Ketika Anda menerjemahkan kode imperatif ke dalam bahasa fungsional, salah satu kesulitannya adalah mengatasi kode yang dapat keluar dengan beberapa cara berbeda. Misalnya, kode dapat mengembalikan atau menaikkan pengecualian. Atau, badan loop dapat melanjutkan untuk memeriksa kondisi lagi atau keluar dari loop sama sekali (
break
membangun). Ada dua cara utama untuk mengatasinya:Continue | Break
.Gaya kelanjutan-kelanjutan adalah bagaimana struktur data dimasukkan ke dalam kalkulus lambda murni. Misalnya, ketika Anda menyatakan true sebagaiλ x , y. x dan salah sebagai λ x , y. y , argumennya x dan y adalah dua kemungkinan kelanjutan, dan boolean adalah pernyataan "jika" yang memilih salah satu atau kelanjutan lainnya.
Dalam gaya kelanjutan-lewat,
diterjemahkan ke
Dalam penerjemahan suatu program dalam bahasa imperatif tipikal dengan gaya kelanjutan-kelanjutan, kelanjutan selalu menjadi hal terakhir yang dijalankan oleh sepotong kode. Misalnya, kelanjutan di
body
atas dijalankan setelah semua kodebody
, jadi pengoptimalan panggilan ekor menghasilkan pembebasan semua variabel lokalbody
sebelum menjalankan kelanjutan.Beberapa bahasa menawarkan kelanjutan kelas satu dengan konstruksi seperti panggilan-dengan-kelanjutan saat ini . Panggilan / cc pada umumnya tidak dapat menerima pengoptimalan panggilan - ini sebenarnya bisa menjadi operasi yang agak mahal karena dapat menyebabkan duplikasi seluruh kondisi program.
sumber