Saya memiliki pengalaman menulis alat kecil di Haskell dan saya merasa sangat intuitif untuk digunakan, terutama untuk menulis filter (menggunakan interact
) yang memproses input standar mereka dan menyalurkannya ke output standar.
Baru-baru ini saya mencoba menggunakan satu filter seperti itu pada file yang sekitar 10 kali lebih besar dari biasanya dan saya mendapat Stack space overflow
kesalahan.
Setelah melakukan beberapa pembacaan (misalnya di sini dan di sini ) saya telah mengidentifikasi dua pedoman untuk menghemat ruang tumpukan (Haskeller berpengalaman, perbaiki saya jika saya menulis sesuatu yang tidak benar):
- Hindari panggilan fungsi rekursif yang tidak berulang-ulang (ini berlaku untuk semua bahasa fungsional yang mendukung optimisasi panggilan-balik).
- Perkenalkan
seq
untuk memaksa evaluasi awal sub-ekspresi sehingga ekspresi tidak tumbuh terlalu besar sebelum dikurangi (ini khusus untuk Haskell, atau setidaknya untuk bahasa yang menggunakan evaluasi malas).
Setelah memasukkan lima atau enam seq
panggilan dalam kode saya, alat saya berjalan dengan lancar lagi (juga pada data yang lebih besar). Namun, saya menemukan kode asli sedikit lebih mudah dibaca.
Karena saya bukan programmer Haskell yang berpengalaman, saya ingin bertanya apakah memperkenalkan seq
dengan cara ini adalah praktik yang umum, dan seberapa sering orang akan melihat seq
kode produksi Haskell. Atau apakah ada teknik yang memungkinkan untuk menghindari penggunaan seq
terlalu sering dan masih menggunakan sedikit ruang stack?
Jawaban:
Sayangnya ada beberapa kasus ketika seseorang harus menggunakan
seq
untuk mendapatkan program yang efisien / bekerja dengan baik untuk data besar. Jadi dalam banyak kasus, Anda tidak dapat melakukannya tanpa kode produksi. Anda dapat menemukan informasi lebih lanjut di Real World Haskell, Bab 25. Profiling dan optimalisasi .Namun, ada beberapa kemungkinan cara menghindari penggunaan
seq
secara langsung. Ini dapat membuat kode lebih bersih dan lebih kuat. Beberapa ide:interact
. Malas IO diketahui memiliki masalah dengan mengelola sumber daya (bukan hanya memori) dan iteratee dirancang persis untuk mengatasi hal ini. (Saya sarankan untuk menghindari IO yang malas sama sekali tidak peduli seberapa besar data Anda - lihat Masalah dengan I / O malas .)seq
langsung menggunakan (atau mendesain sendiri) kombinator seperti foldl ' atau foldr' atau versi ketat perpustakaan (seperti Data.Map.Strict atau Control.Monad.State.Strict ) yang dirancang untuk perhitungan yang ketat.seq
dengan pencocokan pola yang ketat. Mendeklarasikan bidang konstruktor yang ketat dapat berguna dalam beberapa kasus.rseq
) atau NF penuh (rdeepseq
) juga. Ada banyak metode utilitas untuk bekerja dengan koleksi, menggabungkan strategi, dll.sumber
ByteString
.