Ini adalah latihan yang bagus untuk menjadi lebih fasih dalam bahasa pemrograman yang ingin Anda pelajari, tetapi hanya sedikit mengutak-atiknya. Ini melibatkan bekerja dengan objek, menggunakan atau mensimulasikan penutupan, dan meregangkan sistem tipe.
Tugas Anda adalah menulis kode untuk mengelola daftar malas, lalu menggunakannya untuk mengimplementasikan algoritma ini untuk menghasilkan angka Fibonacci:
Sampel kode ada di Haskell
let fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
in take 40 fibs
Hasil:
[0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578,5702887,9227465,14930352,24157817,39088169,63245986]
Implementasi daftar malas Anda harus memenuhi pedoman ini:
- Node Daftar adalah salah satu dari tiga hal:
- Nihil - Daftar kosong.
[]
- Kontra - Satu item, dipasangkan dengan Daftar item yang tersisa:
1 : [2,3,4,5]
(:
adalah operator kontra di Haskell) - Thunk - Perhitungan tangguhan yang menghasilkan node Daftar saat diperlukan.
- Nihil - Daftar kosong.
- Ini mendukung operasi berikut:
- nil - Buat daftar kosong.
- kontra - Membangun sel kontra.
- thunk - Construct a Thunk, diberi fungsi yang tidak membutuhkan argumen dan mengembalikan Nil atau Kontra.
- force - Diberikan simpul Daftar:
- Jika Nil atau Kontra, kembalikan saja.
- Jika itu Thunk, panggil fungsinya untuk mendapatkan Nil atau Kontra. Ganti thunk dengan Nil atau Kontra itu, dan kembalikan.
Catatan: Mengganti thunk dengan nilai paksa adalah bagian penting dari definisi "malas" . Jika langkah ini dilewati, algoritma Fibonacci di atas akan terlalu lambat.
- kosong - Lihat apakah simpul Daftar adalah Nil (setelah memaksanya).
- head (aka "car") - Dapatkan item pertama dari daftar (atau cocokkan jika nihil).
- tail (alias "cdr") - Dapatkan elemen setelah kepala daftar (atau melempar jika itu nol).
- zipWith - Diberikan fungsi biner (misalnya
(+)
) dan dua (mungkin tak terbatas) daftar, menerapkan fungsi tersebut ke item yang sesuai dari daftar. Contoh:
zipWith (+) [1,2,3] [1,1,10] == [2,3,13]
- take - Diberikan nomor N dan daftar (mungkin tak terbatas), ambil item N pertama dari daftar.
- print - Cetak semua item dalam daftar. Ini harus bekerja secara bertahap ketika diberi daftar panjang atau tidak terbatas.
fibs
menggunakan dirinya sendiri dalam definisi sendiri. Menyiapkan rekursi malas agak rumit; Anda harus melakukan sesuatu seperti ini:- Alokasikan thunk untuk
fibs
. Biarkan dalam kondisi dummy untuk saat ini. - Tentukan fungsi thunk, yang tergantung pada referensi ke
fibs
. - Perbarui thunk dengan fungsinya.
Anda mungkin ingin menyembunyikan pipa ledeng ini dengan mendefinisikan fungsi
fix
yang memanggil fungsi Daftar-kembali dengan nilai baliknya sendiri. Pertimbangkan untuk tidur sebentar agar ide ini bisa masuk.- Alokasikan thunk untuk
Polimorfisme (kemampuan untuk bekerja dengan daftar jenis barang apa pun) tidak diperlukan, tetapi lihat apakah Anda dapat menemukan cara untuk melakukannya yang idiomatis dalam bahasa Anda.
- Jangan khawatir tentang manajemen memori. Bahkan bahasa dengan pengumpulan sampah memiliki kecenderungan untuk membawa benda-benda yang tidak akan pernah Anda gunakan lagi (misalnya pada tumpukan panggilan), jadi jangan heran jika program Anda membocorkan memori saat melintasi daftar yang tak terbatas.
Jangan ragu untuk menyimpang sedikit dari pedoman ini untuk mengakomodasi rincian bahasa Anda, atau untuk mengeksplorasi pendekatan alternatif untuk daftar malas.
Aturan:
- Pilih bahasa yang tidak Anda kenal dengan baik. Saya tidak bisa "meminta" ini, karena itu tag "sistem kehormatan". Namun, pemilih dapat memeriksa riwayat Anda untuk melihat bahasa apa yang Anda posting.
Jangan gunakan dukungan daftar malas bawaan bahasa Anda untuk melakukan semuanya. Posting sesuatu yang substansial atau setidaknya menarik.
Haskell cukup banyak keluar. Yaitu, kecuali Anda melakukan sesuatu seperti ini:
data List a = IORef (ListNode a) data ListNode a = Nil | Cons !a !(List a) | Thunk !(IO (ListNode a))
Catatan: Evaluasi Haskell yang tidak ketat tidak terlarang, tetapi implementasi daftar malas Anda tidak seharusnya menurunkan kemampuannya langsung dari sana. Bahkan, akan menarik untuk melihat solusi yang efisien, murni fungsional yang tidak memerlukan kemalasan.
Python:
- Jangan gunakan itertools.
- Generator baik-baik saja, tetapi Anda menggunakannya, Anda harus menemukan beberapa cara untuk menghafal nilai yang dipaksakan.
zipWith (+) [1,2,3,4,5] [0,0,0] == [1,2,3]
,. Namun, ini tidak masalah untuk algoritma Fibonacci di atas, karena kedua argumen untuk zipWith adalah daftar tanpa batas.
fibs
dengan benar, karena itu tergantung pada dirinya sendiri. Saya memperbarui pertanyaan untuk menguraikan rekursi malas. FUZxxl menemukan jawabannya sendiri.
zipWith
dua daftar dengan panjang yang berbeda?