Ini sebenarnya hanya konstruktor data normal yang kebetulan didefinisikan dalam Prelude , yang merupakan pustaka standar yang diimpor secara otomatis ke dalam setiap modul.
Apa Maybe itu, Secara Struktural
Definisi tersebut terlihat seperti ini:
data Maybe a = Just a
| Nothing
Deklarasi itu mendefinisikan sebuah tipe, Maybe a
yang diparameterisasi oleh variabel tipe a
, yang berarti Anda dapat menggunakannya dengan tipe apa pun sebagai pengganti a
.
Membangun dan Menghancurkan
Tipe ini memiliki dua konstruktor, Just a
dan Nothing
. Ketika suatu tipe memiliki banyak konstruktor, itu berarti bahwa nilai tipe harus dibangun hanya dengan salah satu konstruktor yang memungkinkan. Untuk tipe ini, nilai dibangun melalui Just
atau Nothing
, tidak ada kemungkinan (non-error) lainnya.
Karena Nothing
tidak memiliki tipe parameter, ketika digunakan sebagai konstruktor, ia menamai nilai konstan yang merupakan anggota tipe Maybe a
untuk semua tipe a
. Tetapi Just
konstruktor memiliki parameter tipe, yang berarti bahwa ketika digunakan sebagai konstruktor, ia bertindak seperti fungsi dari tipe a
ke Maybe a
, yaitu memiliki tipea -> Maybe a
Jadi, konstruktor tipe membangun nilai tipe itu; sisi lain adalah ketika Anda ingin menggunakan nilai itu, dan di situlah pencocokan pola berperan. Tidak seperti fungsi, konstruktor dapat digunakan dalam ekspresi pengikatan pola, dan ini adalah cara di mana Anda dapat melakukan analisis kasus nilai yang termasuk dalam tipe dengan lebih dari satu konstruktor.
Untuk menggunakan Maybe a
nilai dalam pencocokan pola, Anda perlu memberikan pola untuk setiap konstruktor, seperti:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
Dalam ekspresi kasus tersebut, pola pertama akan cocok jika nilainya adalah Nothing
, dan pola kedua akan cocok jika nilai itu dibuat Just
. Jika yang kedua cocok, itu juga mengikat nama val
ke parameter yang diteruskan ke Just
konstruktor ketika nilai yang Anda cocokkan dibuat.
What Maybe Means
Mungkin Anda sudah terbiasa dengan cara kerjanya; sebenarnya tidak ada keajaiban untuk Maybe
nilai, itu hanya Haskell Algebraic Data Type (ADT) normal. Tapi itu digunakan cukup banyak karena secara efektif "mengangkat" atau memperluas tipe, seperti Integer
dari contoh Anda, ke dalam konteks baru di mana ia memiliki nilai ekstra ( Nothing
) yang merepresentasikan kurangnya nilai! Sistem tipe kemudian mengharuskan Anda memeriksa nilai ekstra itu sebelum memungkinkan Anda mendapatkan nilai Integer
yang mungkin ada di sana. Ini mencegah sejumlah besar bug.
Banyak bahasa saat ini menangani nilai "tanpa nilai" semacam ini melalui referensi NULL. Tony Hoare, seorang ilmuwan komputer terkemuka (ia menemukan Quicksort dan merupakan pemenang Turing Award), menganggap ini sebagai "kesalahan miliaran dolar" . Jenis Mungkin bukan satu-satunya cara untuk memperbaikinya, tetapi telah terbukti menjadi cara yang efektif untuk melakukannya.
Mungkin sebagai Functor
Ide untuk mengubah satu tipe ke tipe lain sehingga operasi pada tipe lama juga bisa diubah untuk bekerja pada tipe baru adalah konsep di balik kelas tipe Haskell yang dipanggil Functor
, yang Maybe a
memiliki instance berguna.
Functor
menyediakan metode yang dipanggil fmap
, yang memetakan fungsi yang berkisar pada nilai dari tipe dasar (seperti Integer
) ke fungsi yang berkisar pada nilai dari tipe yang diangkat (seperti Maybe Integer
). Sebuah fungsi yang diubah dengan fmap
untuk mengerjakan Maybe
nilai bekerja seperti ini:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
Jadi jika Anda memiliki Maybe Integer
nilai m_x
dan Int -> Int
fungsi f
, Anda dapat fmap f m_x
menerapkan fungsi tersebut f
secara langsung ke Maybe Integer
tanpa khawatir apakah fungsi tersebut benar-benar bernilai atau tidak. Faktanya, Anda dapat menerapkan seluruh rangkaian Integer -> Integer
fungsi yang diangkat ke Maybe Integer
nilai dan hanya perlu mengkhawatirkan pemeriksaan secara eksplisit untuk Nothing
sekali saat Anda selesai.
Mungkin sebagai Monad
Saya tidak yakin seberapa akrab Anda dengan konsep a Monad
yet, tetapi Anda setidaknya pernah menggunakan IO a
sebelumnya, dan tipe tanda tangan IO a
terlihat sangat mirip Maybe a
. Meskipun IO
spesial karena tidak mengekspos konstruktornya kepada Anda dan dengan demikian hanya dapat "dijalankan" oleh sistem runtime Haskell, ia juga merupakan Functor
tambahan untuk menjadi a Monad
. Faktanya, ada perasaan penting di mana a Monad
hanyalah jenis khusus Functor
dengan beberapa fitur tambahan, tetapi ini bukan tempat untuk membahasnya.
Bagaimanapun, Monad menyukai IO
tipe peta menjadi tipe baru yang merepresentasikan "komputasi yang menghasilkan nilai" dan Anda dapat mengangkat fungsi menjadi Monad
tipe melalui fmap
fungsi yang sangat mirip yang disebut liftM
yang mengubah fungsi reguler menjadi "komputasi yang menghasilkan nilai yang diperoleh dengan mengevaluasi fungsi."
Anda mungkin telah menebak (jika Anda telah membaca sejauh ini) itu Maybe
juga a Monad
. Ini mewakili "perhitungan yang bisa gagal mengembalikan nilai". Sama seperti fmap
contoh, ini memungkinkan Anda melakukan banyak komputasi tanpa harus memeriksa kesalahan secara eksplisit setelah setiap langkah. Dan pada kenyataannya, cara Monad
instance dibuat, penghitungan Maybe
nilai berhenti segera setelah a Nothing
ditemukan, jadi ini seperti pembatalan langsung atau pengembalian tak berharga di tengah penghitungan.
Anda Mungkin Bisa Menulis
Seperti yang saya katakan sebelumnya, tidak ada yang melekat pada Maybe
tipe yang dimasukkan ke dalam sintaks bahasa atau sistem runtime. Jika Haskell tidak menyediakannya secara default, Anda dapat menyediakan semua fungsinya sendiri! Nyatanya, Anda tetap bisa menulisnya sendiri, dengan nama berbeda, dan mendapatkan fungsi yang sama.
Semoga Anda memahami Maybe
jenis dan konstruktornya sekarang, tetapi jika masih ada yang kurang jelas, beri tahu saya!
Maybe
mana bahasa lain akan digunakannull
ataunil
(dengan kata jahatNullPointerException
bersembunyi di setiap sudut). Sekarang bahasa lain mulai menggunakan konstruksi ini juga: Scala asOption
, dan bahkan Java 8 akan memilikiOptional
tipenya.Sebagian besar jawaban saat ini adalah penjelasan yang sangat teknis tentang bagaimana
Just
dan teman bekerja; Saya pikir saya mungkin akan mencoba menjelaskan untuk apa itu.Banyak bahasa yang memiliki nilai seperti
null
itu yang dapat digunakan sebagai pengganti nilai sebenarnya, setidaknya untuk beberapa jenis. Hal ini membuat banyak orang sangat marah dan secara luas dianggap sebagai tindakan yang buruk. Namun, terkadang berguna untuk memiliki nilai sepertinull
untuk menunjukkan tidak adanya sesuatu.Haskell memecahkan masalah ini dengan membuat Anda secara eksplisit menandai tempat-tempat di mana Anda dapat memiliki
Nothing
(versinya anull
). Pada dasarnya, jika fungsi Anda biasanya mengembalikan tipeFoo
, itu seharusnya mengembalikan tipeMaybe Foo
. Jika Anda ingin menunjukkan bahwa tidak ada nilai, kembalikanNothing
. Jika Anda ingin mengembalikan nilaibar
, Anda harus mengembalikanJust bar
.Jadi pada dasarnya, jika Anda tidak bisa memiliki
Nothing
, Anda tidak perluJust
. Jika Anda dapat memilikiNothing
, Anda memang membutuhkanJust
.Tidak ada yang ajaib tentang
Maybe
; itu dibangun di atas sistem tipe Haskell. Itu berarti Anda dapat menggunakan semua trik pencocokan pola Haskell yang biasa dengannya.sumber
Diberikan sebuah tipe
t
, nilai dariJust t
adalah nilai tipe yang sudah adat
, dimanaNothing
merepresentasikan kegagalan untuk mencapai sebuah nilai, atau kasus dimana memiliki sebuah nilai akan menjadi tidak berarti.Dalam contoh Anda, memiliki keseimbangan negatif tidak masuk akal, jadi jika hal seperti itu terjadi, diganti dengan
Nothing
.Untuk contoh lain, ini bisa digunakan dalam pembagian, mendefinisikan fungsi pembagian yang mengambil
a
danb
, dan mengembalikanJust a/b
jikab
bukan nol, danNothing
sebaliknya. Ini sering digunakan seperti ini, sebagai alternatif yang nyaman untuk pengecualian, atau seperti contoh Anda sebelumnya, untuk mengganti nilai yang tidak masuk akal.sumber
Just
, kode Anda tidak akan salah ketik. AlasannyaJust
adalah untuk mempertahankan tipe yang tepat. Ada tipe (sebenarnya A monad, tetapi lebih mudah untuk dianggap hanya sebagai tipe)Maybe t
, yang terdiri dari elemen bentukJust t
danNothing
. KarenaNothing
memiliki tipeMaybe t
, ekspresi yang dapat mengevaluasi salah satuNothing
atau beberapa nilai tipet
tidak diketik dengan benar. Jika suatu fungsi kembaliNothing
dalam beberapa kasus, ekspresi apa pun yang menggunakan fungsi itu harus memiliki beberapa cara untuk memeriksanya (isJust
atau pernyataan kasus), untuk menangani semua kemungkinan kasus.Maybe t
adalah hanya tipe. Fakta bahwa adaMonad
contoh untukMaybe
tidak mengubahnya menjadi sesuatu yang bukan tipe.Fungsi total a-> b dapat menemukan nilai tipe b untuk setiap kemungkinan nilai tipe a.
Di Haskell tidak semua fungsi bersifat total. Dalam kasus khusus ini, fungsi
lend
tidak total - tidak ditentukan untuk kasus ketika saldo kurang dari cadangan (walaupun, menurut selera saya akan lebih masuk akal untuk tidak mengizinkan saldo baru menjadi kurang dari cadangan - sebagaimana adanya, Anda dapat meminjam 101 dari keseimbangan 100).Desain lain yang berhubungan dengan fungsi non-total:
lend
dapat ditulis untuk mengembalikan saldo lama, jika kondisi pinjaman tidak terpenuhiIni adalah batasan desain yang diperlukan dalam bahasa yang tidak dapat memaksakan totalitas fungsi (misalnya, Agda dapat, tetapi mengarah ke komplikasi lain, seperti menjadi tidak lengkap).
Masalah dengan mengembalikan nilai khusus atau melempar pengecualian adalah mudah bagi pemanggil untuk mengabaikan penanganan kemungkinan seperti itu secara tidak sengaja.
Masalah dengan secara diam-diam membuang kegagalan juga jelas - Anda membatasi apa yang dapat dilakukan pemanggil dengan fungsi tersebut. Misalnya, jika
lend
saldo lama dikembalikan, penelepon tidak dapat mengetahui apakah saldo telah berubah. Ini mungkin atau mungkin tidak menjadi masalah, tergantung pada tujuan yang dimaksudkan.Solusi Haskell memaksa pemanggil dari fungsi parsial untuk menangani tipe seperti
Maybe a
, atauEither error a
karena tipe kembalian fungsi.Dengan cara ini,
lend
seperti yang didefinisikan, adalah fungsi yang tidak selalu menghitung keseimbangan baru - untuk beberapa keadaan, keseimbangan baru tidak ditentukan. Kami memberi sinyal keadaan ini kepada penelepon dengan mengembalikan nilai khusus Nothing, atau dengan membungkus saldo baru di Just. Penelepon sekarang memiliki kebebasan untuk memilih: menangani kegagalan untuk meminjamkan dengan cara khusus, atau mengabaikan dan menggunakan saldo lama - misalnya ,maybe oldBalance id $ lend amount oldBalance
.sumber
Fungsi
if (cond :: Bool) then (ifTrue :: a) else (ifFalse :: a)
harus memiliki jenisifTrue
danifFalse
.Jadi, saat kita menulis
then Nothing
, kita harus menggunakanMaybe a
type inelse f
sumber
Nothing
danJust newBalance
secara eksplisit.Just
.