Di Haskell, saya bisa menggunakan tipe a -> Maybe b
untuk memodelkan fungsi yang mengembalikan nilai tipe b
, atau mengembalikan apa-apa (gagal).
Jika saya memiliki jenis a1, ..., a(n+1)
dan fungsi f1, ..., fn
, dengan fi :: ai -> Maybe a(i+1)
untuk semua i
, 1 <= i <= n
, aku dapat rantai fungsi dengan menggunakan >>=
operator Maybe
monad dan menulis:
f1 x >>= f2 >>= f3 >>=... >>= fn
The >>=
Memastikan operator yang masing-masing fungsi diterapkan selama pendahulunya telah kembali nilai yang berarti. Segera setelah fungsi dalam rantai gagal, seluruh rantai gagal (kembali Nothing
) dan fungsi lebih lanjut dalam rantai tidak dievaluasi.
Saya memiliki pola yang agak mirip di mana saya ingin mencoba beberapa fungsi pada input yang sama, dan kembali segera setelah satu fungsi berhasil . Jika semua fungsi gagal (kembali Nothing
), seluruh perhitungan harus gagal. Lebih tepatnya, saya memiliki fungsi f1, ..., fn :: a -> Maybe b
dan saya mendefinisikan fungsi
tryFunctions :: [a -> Maybe b] -> a -> Maybe b
tryFunctions [] _ = Nothing
tryFunctions (f : fs) x = case f x of
Nothing -> tryFunctions fs x
r@(Just _) -> r
Dalam arti tertentu, ini adalah ganda bagi Maybe
monad karena perhitungan berhenti pada keberhasilan pertama dan bukan pada kegagalan pertama.
Tentu saja, saya dapat menggunakan fungsi yang saya tulis di atas, tetapi saya bertanya-tanya apakah ada cara yang lebih baik, mapan dan idiomatis untuk mengekspresikan pola ini di Haskell.
return f1 ?? f2 ?? f3 ?? DefaultValue;
Alternative
yang merupakan simbol operator infiks<|>
dan didefinisikan dalam istilah MonoidJawaban:
Diberikan set tertutup (jumlah elemen tetap)
S
dengan elemen{a..z}
dan operator biner*
:Ada elemen identitas tunggal
i
sehingga:forall x in S: i * x = x = x * i
Operator bersifat asosiatif sehingga:
forall a, b, c in S: a * (b * c) = (a * b) * c
Anda memiliki monoid.
Sekarang diberi monoid apa pun, Anda dapat mendefinisikan fungsi biner
f
sebagai:Artinya adalah bahwa untuk contoh
Maybe
monoid (Nothing
apakah elemen identitas dilambangkan di atas sebagaii
):Anehnya, saya tidak dapat menemukan fungsi yang tepat ini di perpustakaan default, yang kemungkinan karena pengalaman saya sendiri. Jika ada orang lain yang bisa menjadi sukarelawan ini, saya akan sangat menghargainya.
Inilah implementasi yang saya simpulkan dari contoh di atas:
Contoh:
Kemudian jika Anda ingin menggunakan daftar fungsi sebagai input ...
contoh:
sumber
<|>
memperlakukan identitas monoid dengan cara khusus. Tidak bisakah seseorang memilih elemen sewenang-wenang dari set arbitrer untuk memainkan peran khusus itu? Mengapa himpunan harus monoid dan elemen khusus<|>
menunjukkan identitasnya?<|>
tidak bergantung pada monoid dan saya memiliki semua ini bercampur? Itu bergantung padaAlternative
typeclass. Untuk memastikan - Aku sedang melihat jawaban saya sendiri dan menyadari itu tidak benar karena[1,2] <|> [3]
memberikan terduga[1,2,3]
sehingga segala sesuatu tentang menggunakan kelas jenis monoid untuk mengidentifikasi identitas yang benar - dan kunci lainnya adalah associativity adalah diperlukan untuk mendapatkan perilaku yang diharapkan , mungkinAlternative
tidak memberikan perilaku yang saya pikir begitu saja ...f
untuk melihat mengapa asosiatif adalah suatu keharusan.sumber
Maybe
... Solusi saya dibatasi olehEq
, entah bagaimana saya merasa kita berdua kehilangan sesuatu yang tersedia secaraMonoid
umum ...either
?Monoid
jadi apa pun dengan elemen identitas dapat memiliki satu set fungsi 2 (saya pikir ini adalah jenis bidang biner), di mana salah satu fungsi memilih identitas daripada yang lain, dan fungsi lainnya selalu memilih elemen non-identitas. Saya hanya tidak tahu bagaimana melakukan ini tanpaEq
mengetahui nilai manaidentity
atau tidak .. jelas dalam monoids aditif atau multiplikasi Anda mendapatkan fungsi tangga secara default (selalu memilih elemen non-identitas menggunakan fungsi biner monoids)foldMap
dapat digunakan sebagai penggantimconcat . map
Ini kedengarannya seperti mengganti kegagalan dengan daftar keberhasilan
Anda berbicara tentang
Maybe a
daripada[a]
, tetapi pada kenyataannya mereka sangat mirip: kita dapat menganggapnyaMaybe a
seperti[a]
, kecuali itu dapat mengandung paling banyak satu elemen (yaitu.Nothing ~= []
DanJust x ~= [x]
).Dalam hal daftar, Anda
tryFunctions
akan sangat sederhana: terapkan semua fungsi ke argumen yang diberikan kemudian gabungkan semua hasil bersama-sama.concatMap
akan melakukan ini dengan baik:Dengan cara ini, kita dapat melihat bahwa
<|>
operator untukMaybe
bertindak seperti penggabungan untuk 'daftar dengan paling banyak satu elemen'.sumber
Dalam semangat Conal, pecah menjadi operasi sederhana yang lebih kecil.
Dalam hal ini,
asum
dariData.Foldable
manakah bagian utama.Atau, sebagai balasan ala Jimmy Hoffa Anda dapat menggunakan
Monoid
instance untuk(->)
tetapi kemudian Anda membutuhkanMonoid
instance untukMaybe
dan yang standar tidak melakukan apa yang Anda inginkan. Anda inginkanFirst
dariData.Monoid
.(Atau
mconcat
untuk versi yang lebih lama dan lebih terspesialisasifold
.)sumber