Apakah bahasa pemrograman fungsional memiliki lebih banyak peluang untuk melakukan optimasi waktu kompilasi?

10

Saya sedang membaca buku "Pemrograman Fungsional untuk Dunia Nyata". Ini dimulai dengan perbandingan antara bahasa pemrograman imperatif dan fungsional. Dan itu menyatakan bagaimana 'nilai' dan 'ekspresi' dalam pemrograman fungsional berbeda dari 'variabel' dan 'fungsi' pemrograman imperatif. Dari diskusi saya semacam mengembangkan ide bahwa -

Bahasa pemrograman fungsional memiliki lebih banyak kesempatan untuk melakukan kompilasi optimasi waktu daripada rekan-rekan imperatif mereka.

Apakah itu benar

Gulshan
sumber

Jawaban:

16

Bahasa pemrograman fungsional melakukan lebih banyak waktu kompilasi optimasi. Salah satu alasannya adalah kemurnian - konkurensi sepele karena tidak ada keadaan. Jadi kompiler dapat mengambil dua cabang dan menggabungkannya dengan mudah tanpa mengubah perilaku program.

Pada saat yang sama, apa pun yang dapat dihitung tanpa status (yaitu apa pun yang non-monadik dalam haskell) dapat dihitung sebelumnya oleh kompiler, tetapi perhitungan seperti itu bisa mahal dan dengan demikian mungkin hanya dilakukan sebagian.

Selain itu, apa pun yang tidak diperlukan secara komputasi dapat sepenuhnya dioptimalkan dari program.

alternatif
sumber
1
+1: Pemrograman gratis efek samping sangat, sangat mudah dioptimalkan.
S.Lott
@ mathepic: sebenarnya paralelisasi (dalam Haskell) terjadi pada kedua waktu kompilasi dan saat run Waktu kompilasi memutuskan apakah perlu membuat shard (seed thread) atau tidak dan menjalankan run-time shard sebanyak mungkin, tergantung pada jumlah utas yang Anda tentukan. Jika Anda hanya menentukan utas tunggal, pecahan dibuat, tetapi mereka diproses satu demi satu.
Matthieu M.
2
@mathepic: penggunaan kemurnian lainnya -> kemalasan dan tidak adanya perhitungan. Jika Anda dapat membuktikan bahwa nilainya tidak diperlukan, lepaskan seluruh perhitungan. Jika mungkin diperlukan, gunakan pemalas malas. Jika Anda tahu itu akan diperlukan, hitung lurus ke depan (untuk menghindari overhead yang malas). Purity (hanya) luar biasa :)
Matthieu M.
@Matthieu poin bagus
alternatif
1
@Masse Bahkan monad IO murni. Hanya saja hasil "menjalankan" monad IO tidak.
alternatif
7

Bahwa pada prinsipnya ada lebih banyak kompilasi kemungkinan optimisasi waktu untuk bahasa fungsional daripada rekan imperatif mereka mungkin benar.

Namun yang lebih menarik adalah, jika mereka benar-benar diimplementasikan dalam kompiler saat ini dan seberapa relevan optimasi ini dalam praktik (yaitu kinerja akhir dari kode 'kehidupan nyata (TM)' idiomatik dalam lingkungan produksi, dengan pengaturan kompiler yang dapat diprediksi secara apriori).

mis. pengajuan Haskell untuk Game Benchmarks Bahasa Komputer yang terkenal (seburuk mungkin - tetapi tidak seperti itu - saat ini - sesuatu yang jauh lebih baik di luar sana) memberikan kesan bahwa sejumlah besar waktu telah dihabiskan untuk optimisasi manual, yang dihadapkan dengan klaim tentang "kemungkinan optimisasi kompiler karena insert some property about FP languages here" membuatnya tampak seperti optimisasi (saat ini setidaknya) lebih dari kemungkinan teoretis daripada kenyataan yang relevan.

Saya akan senang meskipun terbukti salah tentang hal ini.

Alexander Battisti
sumber
1
Alasan optimalisasi manual di Haskell lebih berkaitan dengan fakta bahwa operasi "langsung" tertentu agak memakan waktu (dari perspektif kompleksitas) di Haskell. Misalnya, Anda ingin mendapatkan elemen terakhir dari daftar. Di Jawa, itu operasi yang cukup sederhana; di Haskell, pendekatan naif mengharuskan Anda berjalan di seluruh daftar sampai Anda tiba di akhir (karena sifat malas dari daftar), menjadikannya operasi O (n). Itulah (sebagian) di mana optimasi manual dilakukan.
mipadi
2
Saya yakin bahwa ada alasan yang sah untuk optimisasi lintingan tangan Haskell, tetapi mereka yang diperlukan untuk operasi "langsung" memberi kesan bahwa peluang yang lebih besar untuk mengoptimalkan kode (saat ini) hanya relevan dalam teori.
Alexander Battisti
6
Ini lebih banyak perbedaan antara mengoptimalkan algoritma, dan mengoptimalkan kode yang dihasilkan. Ambil contoh C: jika saya menulis algoritma pencarian, saya dapat menulis algoritma naif yang hanya berjalan melalui daftar, atau saya dapat menggunakan pencarian biner. Dalam kedua kasus, kompiler akan mengoptimalkan kode saya, tetapi tidak akan mengubah algoritma pencarian naif menjadi pencarian biner. Banyak optimasi manual dalam kode Haskell lebih berkaitan dengan mengoptimalkan algoritma itu sendiri, daripada mengoptimalkan kode yang dihasilkan.
mipadi
2
@mipadi, tetapi tampaknya versi sederhana dari algoritma Haskell tidak sebagus versi langsung dari algoritma bahasa lain. (Saya curiga karena ketidakcocokan antara model fungsional dan arsitektur komputer) Bahkan jika itu baik dalam menghasilkan kode, itu tidak cukup untuk mengatasi masalah ini.
Winston Ewert
>> buruk seperti itu mungkin << - Apakah Anda tahu apakah itu buruk atau tidak? Apa maksud Anda dengan mengatakan itu "buruk"? Harap spesifik.
igouy
2

Dalam gaya fungsional, aliran nilai melalui suatu program sangat, sangat terlihat (baik bagi kompiler maupun pemrogram). Ini memberi kompiler banyak kelonggaran untuk memutuskan di mana menyimpan nilai, berapa lama menyimpannya, dan sebagainya.

Dalam bahasa imperatif, kompiler menjanjikan pemrogram model di mana sebagian besar variabel sesuai dengan lokasi aktual dalam memori yang tetap ada selama masa hidup yang ditentukan. Secara potensial, pernyataan apa pun dapat membaca dari (atau menulis ke!) Salah satu dari lokasi ini, sehingga kompiler hanya dapat mengganti lokasi memori dengan alokasi register, menggabungkan dua variabel menjadi satu lokasi penyimpanan, atau melakukan optimasi serupa setelah melakukan analisis yang teliti dari mana lain di program variabel yang dapat dirujuk.

Sekarang, ada dua peringatan:

  • Komunitas bahasa pemrograman telah menghabiskan (terbuang?) Banyak upaya selama lima puluh tahun terakhir untuk mengembangkan cara-cara cerdas untuk melakukan analisis ini. Ada trik-trik terkenal seperti pewarnaan register dan sebagainya untuk menyelesaikan beberapa kasus yang lebih mudah; tetapi ini membuat kompiler besar dan lambat, dan kompromi kompilasi yang konstan untuk kualitas kode yang dihasilkan
  • Pada saat yang sama, sebagian besar bahasa pemrograman fungsional juga tidak sepenuhnya fungsional; banyak hal yang sebenarnya perlu dilakukan oleh program, seperti menanggapi I / O yang pada dasarnya tidak berfungsi, sehingga tidak ada kompiler yang bisa sepenuhnya bebas dari trik-trik ini, dan tidak ada bahasa yang menghindarinya sepenuhnya - bahkan Haskell, yang agak terlalu murni untuk seleraku (Your Mileage May Vary) hanya dapat mengontrol dan mematikan komponen-komponen kode Anda yang tidak berfungsi, tidak menghindarinya sama sekali.

Tetapi untuk menjawab pertanyaan umum, ya, sebuah paradigma fungsional memberi kompiler banyak kebebasan untuk mengoptimalkan yang tidak ada dalam pengaturan imperatif.

jimwise
sumber
Segala sesuatu di Haskell fungsional, hanya saja Anda mainadalah fungsi yang mentransformasikan keadaan daripada sesuatu yang menggunakan keadaan itu sendiri.
alternatif
Ya dan tidak - secara konseptual, cukup benar untuk mengatakan bahwa program Haskell adalah fungsi murni atas interaksi pengguna dengan program itu (dan keadaan generator nomor acak sistem, dan latensi jaringan saat ini, dan yang lainnya pada dasarnya input non-fungsional yang ditanggapi program), tetapi dalam praktiknya ini adalah perbedaan tanpa perbedaan.
bersamaan
@jimwise Transparansi referensial adalah perbedaan yang sangat besar.
alternatif
Kecuali Anda tidak benar-benar memilikinya, setidaknya untuk tujuan yang dibahas di sini. Titik operasi seperti IO, atau generasi angka acak, adalah bahwa mereka harus mengembalikan nilai yang berbeda setiap kali mereka dipanggil dengan input yang sama, dan ini secara inheren membatasi penalaran tentang mereka secara fungsional, baik untuk programmer atau kompiler.
bersamaan
1
@mathepic Ya, tentu saja Anda secara konseptual dapat melihat keacakan atau input pengguna (atau latensi jaringan, atau beban sistem) sebagai aliran tanpa batas atau fungsi dari negara bagian ke negara, tetapi ini bukan pandangan yang cocok dengan alasan yang berguna tentang perilaku program oleh Anda atau kompiler Anda - Bob Harper membahas hal ini dengan baik dalam posting terbaru di blognya tentang kurikulum CS fungsional-pemrograman-pertama baru CMU.
bersamaan