Saya baru-baru ini mengalami situasi di mana saya harus melewati fungsi predikat ke fungsi lain, dan cukup sering logika yang saya cari pada dasarnya adalah "apakah nilai ini cocok dengan pola ini?"
Pencocokan pola tampaknya lebih disukai dalam deklarasi, do
blok, dan daftar pemahaman, tetapi ada sejumlah fungsi yang mengambil predikat a -> Bool
, di mana akan sangat berguna untuk melewati suatu pola. Sebagai contoh, takeWhile
, until
, find
, span
, dll
Sejauh ini saya sudah melakukan \a -> case a of MyCons _ -> True; otherwise -> False
, atau menulis fungsi bernama a la let myPred (MyCons _) = True; myPred _ = False in
tetapi mereka berdua tampak sangat jelek dan tidak terlalu idiomatis. Cara "jelas" (dan salah) akan menjadi sesuatu seperti \(MyCons _) -> True
tetapi itu melemparkan kesalahan karena menjadi parsial, secara alami, dan bahkan kemudian rasanya seperti harus ada cara yang lebih bersih.
Apakah ada cara yang lebih ringkas / bersih untuk melakukan hal semacam ini? Atau apakah saya melakukan sesuatu yang sepenuhnya salah?
let
klausa yang tidak Anda sukai - walaupun saya lebih sukawhere
klausa yang setara sehingga ini tidak mengacaukan definisi utama. Tentu saja jika Anda membutuhkan utilitas ini lebih dari sekali maka Anda akan mendefinisikannya sebagai fungsi tingkat atas.let myPred...
gaya itu buruk , tetapi rasanya jauh lebih jelas daripada yang saya harapkan untuk ide yang sangat sederhana, yang membuat saya bertanya-tanya apakah saya menggonggong pohon yang salah.maybe :: b -> (a -> b) -> Maybe a -> b
danbool :: a -> a -> Bool -> a
, kemudian gunakan dengan fungsi penghasil Boolean sebagai argumen. misalnyamyCons z f (MyCons x) = f x ; myCons z f _ = z
, lalu teleponmyCons False (const True) aMyConsValue
. ini hampir seperti yang Anda tulis, hanya memiliki satu tingkat "tipuan" / "abstraksi" lagi melalui argumen fungsional, dimasukkan ke dalamnya.Jawaban:
Anda dapat menggunakan LambdaCase Ekstensi Bahasa untuk digunakan
\case MyCons _ -> True; _ -> False
, meskipun ini tidak menyimpan banyak karakter.Saya percaya Anda bisa menulis serangkaian fungsi
constructedWith :: (Generic a) => (b -> a) -> a -> Bool
,constructedWith2 :: (Generic a) => (b -> c -> a) -> a -> Bool
tapi saya tidak cukup kompeten dengan Generics untuk mengimplementasikannya tanpa beberapa jam menguji semuanya. Saya akan mencoba ini, dan mengedit jawaban saya jika saya bisa mengetahuinya, atau jika itu jalan buntu.EDIT: Ya, Anda bisa melakukannya! Berikut ini tautan ke kode saya, yang mengimplementasikan semuanya dari awal:
https://repl.it/@lalaithion/ConstructedWith
Namun, menggunakan sesuatu seperti http://hackage.haskell.org/package/generic-deriving-1.13.1/docs/Generics-Deriving-ConNames.html untuk semua pemipaan kode generik mungkin lebih baik.
sumber