Pada dasarnya, bahasa yang tidak murni tidak benar-benar berbeda dari bahasa imperatif yang lebih akrab, terutama sekarang karena banyak trik fungsional telah disalin. Yang berbeda adalah gaya - bagaimana Anda memecahkan masalah.
Apakah Anda menganggap Haskell sebagai murni, atau menganggap monad IO sebagai ketidakmurnian, gaya Haskell adalah bentuk ekstrim dari gaya ini dan layak untuk dipelajari.
Haskell IO Monad berasal dari teori matematika (tentu saja) monad. Namun, untuk programer yang penting, saya pikir cara mundur untuk tiba di monad lebih masuk akal.
Fase satu - bahasa fungsional murni dapat dengan mudah mengembalikan nilai string besar sebagai hasilnya. String besar ini dapat menjadi kode sumber dari program imperatif, diturunkan dengan cara fungsional murni dari beberapa parameter yang menentukan persyaratan. Anda kemudian dapat membangun kompilator "tingkat lebih tinggi" yang menjalankan pembuat kode Anda, lalu secara otomatis memasukkan kode yang dihasilkan ke kompiler bahasa imperatif.
Fase dua - daripada menghasilkan kode sumber tekstual, Anda menghasilkan pohon sintaksis yang sangat diketik. Kompiler bahasa imperatif Anda diserap ke dalam kompiler "level lebih tinggi" Anda, dan menerima AST secara langsung sebagai kode sumber. Ini jauh lebih dekat dengan apa yang Haskell lakukan.
Ini masih canggung. Misalnya Anda memiliki dua jenis fungsi yang berbeda - yang dievaluasi selama fase pembuatan kode dan yang dijalankan ketika program yang dihasilkan dijalankan. Ini agak seperti perbedaan antara fungsi dan template di C ++.
Jadi, untuk fase 3, buat keduanya sama - fungsi yang sama dengan sintaksis yang sama dapat dievaluasi sebagian selama "pembuatan kode", atau dievaluasi sepenuhnya, atau tidak dievaluasi sama sekali. Lebih lanjut, buang semua simpul AST looping yang mendukung rekursi. Bahkan, buang ide AST node sebagai jenis data khusus sama sekali - tidak memiliki AST "nilai literal", hanya punya nilai dll.
Inilah yang dilakukan oleh IO monad - operator pengikat adalah cara menyusun "tindakan" untuk membentuk program. Tidak ada yang istimewa - hanya fungsi. Banyak ekspresi dan fungsi dapat dievaluasi selama "pembuatan kode", tetapi yang bergantung pada efek samping I / O harus ditunda evaluasi sampai run-time - bukan oleh aturan khusus, tetapi sebagai konsekuensi alami dari ketergantungan data pada ekspresi.
Monads secara umum hanyalah generalisasi - mereka memiliki antarmuka yang sama, tetapi menerapkan operasi abstrak secara berbeda, jadi alih-alih mengevaluasi ke deskripsi kode imperatif mereka mengevaluasi ke sesuatu yang lain sebagai gantinya. Memiliki antarmuka yang sama berarti ada beberapa hal yang dapat Anda lakukan untuk monad tanpa peduli monad mana, yang ternyata bermanfaat.
Deskripsi ini tidak diragukan lagi akan membuat purists head meledak, tetapi bagi saya itu menjelaskan beberapa alasan sebenarnya mengapa Haskell menarik. Ini mengaburkan batas antara pemrograman dan metaprogramming, dan menggunakan alat pemrograman fungsional untuk menemukan kembali pemrograman imperatif tanpa memerlukan sintaksis khusus.
Kritik yang saya miliki tentang C ++ templates adalah bahwa mereka adalah semacam bahasa terjemahan fungsional yang rusak murni dalam bahasa imperatif - untuk mengevaluasi fungsi dasar yang sama pada waktu kompilasi daripada pada saat run-time Anda harus mengimplementasikannya kembali menggunakan gaya yang sama sekali berbeda pengkodean. Dalam Haskell, sementara kenajisan harus diberi label seperti itu dalam tipenya, fungsi yang sama persis dapat dievaluasi baik dalam arti meta-pemrograman dan dalam arti run-time non-meta-pemrograman dalam program yang sama - tidak ada garis keras antara pemrograman dan metaprogramming.
Yang mengatakan, ada beberapa hal metaprogramming yang Haskell standar tidak bisa lakukan, pada dasarnya karena tipe (dan mungkin beberapa hal lainnya) bukan nilai kelas Ada beberapa varian bahasa yang mencoba mengatasinya.
Banyak hal yang saya katakan tentang Haskell dapat diterapkan dalam bahasa fungsional yang tidak murni - dan kadang-kadang bahkan bahasa imperatif. Haskell berbeda karena Anda tidak punya pilihan selain mengambil pendekatan ini - pada dasarnya memaksa Anda untuk mempelajari gaya kerja ini. Anda dapat "menulis C dalam ML", tetapi Anda tidak dapat "menulis C di Haskell" - setidaknya tidak tanpa mengetahui apa yang terjadi di bawah tenda.