Semantik Haskell menggunakan "nilai terbawah" untuk menganalisis makna kode Haskell. Ini bukan sesuatu yang benar-benar Anda gunakan langsung dalam pemrograman Haskell, dan kembaliNone
sama sekali bukan hal yang sama.
Nilai terbawah adalah nilai yang ditentukan oleh semantik Haskell untuk setiap perhitungan yang gagal mengevaluasi ke suatu nilai secara normal. Salah satu cara yang dapat dilakukan komputasi Haskell adalah dengan melemparkan pengecualian! Jadi jika Anda mencoba menggunakan gaya ini di Python, Anda sebenarnya harus membuang pengecualian seperti biasa.
Semantik Haskell menggunakan nilai terbawah karena Haskell malas; Anda dapat memanipulasi "nilai" yang dikembalikan oleh perhitungan yang belum benar-benar berjalan. Anda dapat meneruskannya ke fungsi, menempelkannya di struktur data, dll. Perhitungan yang tidak dievaluasi seperti itu dapat membuang pengecualian atau loop selamanya, tetapi jika kita tidak pernah benar-benar perlu memeriksa nilainya maka perhitungannya akan tidak pernahjalankan dan temukan kesalahannya, dan program keseluruhan kami mungkin berhasil melakukan sesuatu yang didefinisikan dengan baik dan selesai. Jadi tanpa ingin menjelaskan apa yang dimaksud kode Haskell dengan menentukan perilaku operasional yang tepat dari program pada saat runtime, kami sebaliknya menyatakan perhitungan yang salah seperti menghasilkan nilai bawah, dan menjelaskan apa yang berperilaku nilai; pada dasarnya bahwa setiap ekspresi yang perlu bergantung pada properti di semua nilai bawah (selain yang ada) juga akan menghasilkan nilai bawah.
Untuk tetap "murni" semua cara yang mungkin menghasilkan nilai bawah harus diperlakukan sebagai setara. Itu termasuk "nilai dasar" yang mewakili loop tak terbatas. Karena tidak ada cara untuk mengetahui bahwa beberapa loop tak terbatas sebenarnya tidak terbatas (mereka mungkin selesai jika Anda menjalankannya sedikit lebih lama), Anda tidak dapat memeriksa properti apa pun yang memiliki nilai dasar. Anda tidak dapat menguji apakah sesuatu terbawah, tidak dapat membandingkannya dengan hal lain, tidak dapat mengubahnya menjadi string, tidak ada. Yang dapat Anda lakukan dengan meletakkannya adalah tempat (parameter fungsi, bagian dari struktur data, dll) tidak tersentuh dan tidak diperiksa.
Python sudah memiliki bottom seperti ini; itu adalah "nilai" yang Anda dapatkan dari ekspresi yang melempar pengecualian, atau tidak berakhir. Karena Python ketat daripada malas, "pantat" seperti itu tidak dapat disimpan di mana saja dan berpotensi dibiarkan tidak diperiksa. Jadi tidak ada kebutuhan nyata untuk menggunakan konsep nilai bawah untuk menjelaskan bagaimana perhitungan yang gagal mengembalikan nilai masih dapat diperlakukan seolah-olah mereka memiliki nilai. Tetapi tidak ada alasan Anda tidak bisa berpikir seperti ini tentang pengecualian jika Anda mau.
Melontarkan pengecualian sebenarnya dianggap "murni". Ini menangkap pengecualian yang merusak kemurnian - justru karena memungkinkan Anda untuk memeriksa sesuatu tentang nilai dasar tertentu, alih-alih memperlakukan mereka semua secara bergantian. Di Haskell Anda hanya dapat menangkap pengecualian di IO
yang memungkinkan antarmuka tidak murni (sehingga biasanya terjadi pada lapisan yang cukup luar). Python tidak menegakkan kemurnian, tetapi Anda masih bisa memutuskan sendiri fungsi mana yang merupakan bagian dari "lapisan luar yang tidak murni" daripada fungsi murni, dan hanya membiarkan diri Anda menangkap pengecualian di sana.
Mengembalikan None
sebaliknya sama sekali berbeda. None
adalah nilai non-bawah; Anda dapat menguji apakah ada sesuatu yang setara dengannya, dan penelepon fungsi yang kembali None
akan terus berjalan, mungkin menggunakan yang None
tidak sesuai.
Jadi jika Anda berpikir untuk melempar pengecualian dan ingin "kembali ke bawah" untuk meniru pendekatan Haskell, Anda sama sekali tidak melakukan apa pun. Biarkan pengecualian berkembang. Itulah yang dimaksud oleh pemrogram Haskell ketika mereka berbicara tentang suatu fungsi yang mengembalikan nilai terendah.
Tapi bukan itu yang dimaksud programmer fungsional ketika mereka mengatakan untuk menghindari pengecualian. Pemrogram fungsional lebih suka "fungsi total". Ini selalu mengembalikan nilai non-bottom yang valid dari tipe pengembalian mereka untuk setiap input yang mungkin. Jadi fungsi apa pun yang dapat melempar pengecualian bukanlah fungsi total.
Alasan kami menyukai fungsi total adalah bahwa mereka lebih mudah diperlakukan sebagai "kotak hitam" ketika kita menggabungkan dan memanipulasi mereka. Jika saya memiliki fungsi total mengembalikan sesuatu tipe A dan fungsi total yang menerima sesuatu tipe A, maka saya dapat memanggil yang kedua pada output yang pertama, tanpa mengetahui apa - apa tentang implementasi keduanya; Saya tahu saya akan mendapatkan hasil yang valid, tidak peduli bagaimana kode dari salah satu fungsi diperbarui di masa mendatang (selama totalitasnya dipertahankan, dan selama mereka tetap menggunakan jenis tanda tangan yang sama). Pemisahan kekhawatiran ini dapat menjadi bantuan yang sangat kuat untuk refactoring.
Ini juga agak diperlukan untuk fungsi tingkat tinggi yang dapat diandalkan (fungsi yang memanipulasi fungsi lain). Jika saya ingin menulis kode yang menerima fungsi sepenuhnya arbitrer (dengan antarmuka yang dikenal) sebagai parameter saya harus memperlakukannya sebagai kotak hitam karena saya tidak punya cara untuk mengetahui input mana yang dapat memicu kesalahan. Jika saya diberi fungsi total maka tidak ada input yang akan menyebabkan kesalahan. Demikian pula, penelepon fungsi orde tinggi saya tidak akan tahu persis argumen apa yang saya gunakan untuk memanggil fungsi yang mereka sampaikan kepada saya (kecuali jika mereka ingin bergantung pada detail implementasi saya), jadi memberikan fungsi total berarti mereka tidak perlu khawatir tentang apa yang saya lakukan dengannya.
Jadi seorang programmer fungsional yang menyarankan Anda untuk menghindari pengecualian akan lebih suka Anda mengembalikan nilai yang mengkodekan kesalahan atau nilai yang valid, dan mengharuskan untuk menggunakannya Anda siap untuk menangani kedua kemungkinan. Hal-hal seperti Either
jenis atau Maybe
/ Option
jenis adalah beberapa yang paling sederhana pendekatan untuk melakukan hal ini dalam bahasa lainnya sangat diketik (biasanya digunakan dengan sintaks khusus atau fungsi orde tinggi untuk bantuan lem bersama-sama hal-hal yang perlu A
dengan hal-hal yang menghasilkan Maybe<A>
).
Sebuah fungsi yang baik pengembalian None
(jika kesalahan terjadi) atau beberapa nilai (jika tidak ada error) mengikuti tidak dari strategi di atas.
Dalam Python dengan bebek mengetik gaya Either / Maybe tidak digunakan terlalu banyak, sebagai gantinya membiarkan pengecualian dilemparkan, dengan tes untuk memvalidasi bahwa kode bekerja daripada memercayai fungsi menjadi total dan secara otomatis dapat digabungkan berdasarkan jenisnya. Python tidak memiliki fasilitas untuk menegakkan bahwa kode menggunakan hal-hal seperti Mungkin mengetik dengan benar; bahkan jika Anda menggunakannya sebagai masalah disiplin Anda perlu tes untuk benar-benar menggunakan kode Anda untuk memvalidasi itu. Jadi pendekatan pengecualian / bawah mungkin lebih cocok untuk pemrograman fungsional murni dengan Python.