Saya setuju dengan Dietrich Epp: kombinasi dari beberapa hal yang membuat GHC cepat.
Pertama dan terpenting, Haskell sangat tingkat tinggi. Ini memungkinkan kompiler melakukan optimisasi agresif tanpa melanggar kode Anda.
Pikirkan tentang SQL. Sekarang, ketika saya menulis SELECT
pernyataan, itu mungkin terlihat seperti loop keharusan, tetapi tidak . Ini mungkin terlihat seperti loop di semua baris dalam tabel itu mencoba untuk menemukan satu yang cocok dengan kondisi yang ditentukan, tetapi sebenarnya "kompiler" (mesin DB) dapat melakukan pencarian indeks sebagai gantinya - yang memiliki karakteristik kinerja yang sama sekali berbeda. Tetapi karena SQL sangat tingkat tinggi, "kompiler" dapat menggantikan algoritma yang sama sekali berbeda, menerapkan beberapa prosesor atau saluran I / O atau seluruh server secara transparan, dan banyak lagi.
Saya menganggap Haskell sama. Anda mungkin berpikir Anda baru saja meminta Haskell untuk memetakan daftar input ke daftar kedua, memfilter daftar kedua ke daftar ketiga, dan kemudian menghitung berapa banyak item yang dihasilkan. Tetapi Anda tidak melihat GHC menerapkan aturan penulisan ulang aliran-fusi di belakang layar, mengubah semuanya menjadi satu loop kode mesin ketat yang melakukan seluruh pekerjaan dalam sekali melewati data tanpa alokasi - jenis hal yang akan menjadi membosankan, rawan kesalahan dan tidak dapat dipertahankan untuk menulis dengan tangan. Itu hanya sangat mungkin karena kurangnya detail level rendah dalam kode.
Cara lain untuk melihatnya mungkin ... mengapa Haskell tidak boleh cepat? Apa fungsinya yang membuatnya lambat?
Ini bukan bahasa yang ditafsirkan seperti Perl atau JavaScript. Ini bahkan bukan sistem mesin virtual seperti Java atau C #. Ini mengkompilasi sampai ke kode mesin asli, jadi tidak ada overhead di sana.
Tidak seperti bahasa OO [Java, C #, JavaScript ...], Haskell memiliki penghapusan tipe penuh [seperti C, C ++, Pascal ...]. Semua pemeriksaan tipe hanya terjadi pada waktu kompilasi. Jadi tidak ada pemeriksaan run-time untuk memperlambat Anda. (Tidak ada pemeriksaan null-pointer, dalam hal ini. Dalam, katakanlah, Java, JVM harus memeriksa pointer nol dan melemparkan pengecualian jika Anda menghormati satu. Haskell tidak perlu repot dengan pemeriksaan itu.)
Anda mengatakan itu terdengar lambat untuk "membuat fungsi dengan cepat pada saat run-time", tetapi jika Anda melihat dengan sangat hati-hati, Anda sebenarnya tidak melakukannya. Mungkin terlihat seperti yang Anda lakukan, tetapi Anda tidak melakukannya. Jika Anda berkata (+5)
, yah, itu kode-keras ke dalam kode sumber Anda. Itu tidak dapat berubah pada saat run-time. Jadi sebenarnya bukan fungsi yang dinamis. Bahkan fungsi kari benar-benar hanya menyimpan parameter ke dalam blok data. Semua kode yang dapat dieksekusi benar-benar ada pada waktu kompilasi; tidak ada interpretasi run-time. (Tidak seperti beberapa bahasa lain yang memiliki "fungsi eval".)
Pikirkan tentang Pascal. Ini sudah tua dan tidak ada yang benar-benar menggunakannya lagi, tetapi tidak ada yang akan mengeluh bahwa Pascal lambat . Ada banyak hal yang tidak disukai tentang hal itu, tetapi kelambatan sebenarnya bukan salah satunya. Haskell tidak benar-benar melakukan banyak hal yang berbeda dengan Pascal, selain memiliki pengumpulan sampah daripada manajemen memori manual. Dan data yang tidak dapat diubah memungkinkan beberapa optimisasi ke mesin GC [yang kemudian sedikit evaluasi rumit].
Saya pikir masalahnya adalah bahwa Haskell terlihat canggih dan canggih dan tingkat tinggi, dan semua orang berpikir "oh wow, ini benar-benar kuat, pasti sangat lambat! " Tetapi tidak. Atau setidaknya, itu tidak seperti yang Anda harapkan. Ya, ini memiliki sistem tipe yang menakjubkan. Tapi tahukah Anda? Itu semua terjadi pada waktu kompilasi. Dengan run-time, itu hilang. Ya, ini memungkinkan Anda membuat ADT yang rumit dengan sebaris kode. Tapi tahukah Anda? Sebuah ADT hanya C biasa polos union
dari struct
s. Tidak ada lagi.
Pembunuh sebenarnya adalah evaluasi malas. Ketika Anda mendapatkan keketatan / kemalasan kode Anda dengan benar, Anda dapat menulis kode cepat bodoh yang masih elegan dan indah. Tetapi jika Anda salah melakukan hal ini, program Anda berjalan ribuan kali lebih lambat , dan itu benar-benar tidak jelas mengapa ini terjadi.
Sebagai contoh, saya menulis sebuah program kecil yang sepele untuk menghitung berapa kali setiap byte muncul dalam sebuah file. Untuk file input 25KB, program membutuhkan waktu 20 menit untuk menjalankan dan menelan 6 gigabytes RAM! Itu tidak masuk akal !! Tapi kemudian saya menyadari apa masalahnya, menambahkan satu pola bang, dan waktu tayang turun menjadi 0,02 detik .
Ini adalah tempat Haskell pergi tiba-tiba perlahan-lahan. Dan tentu saja butuh waktu untuk terbiasa. Namun seiring waktu, semakin mudah untuk menulis kode yang sangat cepat.
Apa yang membuat Haskell begitu cepat? Kemurnian. Jenis statis. Kemalasan. Tetapi di atas semua itu, karena kompiler tingkat tinggi yang cukup dapat secara radikal mengubah implementasi tanpa melanggar harapan kode Anda.
Tapi saya kira itu hanya pendapat saya ...