Saat ini saya sedang berurusan dengan fungsi yang berjalan seperti ini:
foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)
Dengan kata lain, diberikan daftar, ia menggunakan enam elemen pertama untuk sesuatu, dan jika daftar itu kurang dari enam elemen, ia menggunakan def
sebagai pengganti untuk yang hilang. Ini total, tetapi potongan-potongan itu tidak (hanya suka map fromJust . filter isJust
), jadi saya tidak suka itu. Saya mencoba menulis ulang ini sehingga tidak perlu menggunakan keberpihakan, dan mendapatkan ini:
foo [] = foobar def def def def def def
foo [a] = foobar a def def def def def
foo [a,b] = foobar a b def def def def
foo [a,b,c] = foobar a b c def def def
foo [a,b,c,d] = foobar a b c d def def
foo [a,b,c,d,e] = foobar a b c d e def
foo (a:b:c:d:e:f:_) = foobar a b c d e f
Secara teknis saya melakukan apa yang saya inginkan, tetapi sekarang ini adalah kekacauan yang sangat besar. Bagaimana saya bisa melakukan ini dengan cara yang lebih elegan dan kurang berulang?
haskell
pattern-matching
Joseph Sible-Reinstate Monica
sumber
sumber
uncons :: Default a => [a] -> (a,[a])
yang defaultnyadef
. Atau defaulttakeWithDef
. Dan / atau pola tampilan / sinonim pola. Ini membutuhkan penulisan beberapa kode pembantu pembantu.case xs ++ repeat def of a:b:c:d:e:f:_ -> ...
cukup lokal sehingga saya tidak akan berpikir dua kali tentang hanya menggunakannya dan melewatkan semua mesin tambahan jawaban yang ada memperkenalkan. Secara umum, argumen totalitas global (yang melibatkan invarian yang dipelihara di beberapa fungsi panggilan, misalnya) membuat saya gugup.takeWithDef
tidak dapat digunakan jika mengembalikan daftar reguler, karena kita perlu mencocokkan pola itu: - / Solusi yang tepat adalah apa yang ditulis Daniel di bawah ini dalam jawaban keduanya.uncons
hanya mendapat elemen pertama, jadi itu tidak berguna.Jawaban:
Dengan menggunakan paket aman , Anda dapat menulis, misalnya:
sumber
Ini setidaknya lebih pendek:
Anda dapat dengan mudah melihat bahwa polanya sudah lengkap, tetapi sekarang Anda harus berpikir sedikit untuk melihat bahwa polanya selalu berakhir. Jadi saya tidak tahu apakah Anda dapat menganggapnya sebagai peningkatan.
Kalau tidak, kita bisa melakukannya dengan negara monad, meskipun agak berat:
Saya juga bisa membayangkan menggunakan tipe aliran infinite seperti
karena maka Anda bisa membangun
foo
darirepeat :: a -> S a
,prepend :: [a] -> S a -> S a
dantake6 :: S a -> (a,a,a,a,a,a)
, yang semuanya bisa Total. Mungkin tidak sepadan jika Anda belum memiliki tipe seperti itu.sumber
data S a = a :- S a; infixr 5 :-
itu terlihat cukup bersih;foo xs = case prepend xs (repeat def) of a:-b:-c:-d:-e:-f:-_ -> foobar a b c d e f
.Hanya untuk bersenang-senang (dan tidak disarankan, ini untuk bersenang-senang), inilah cara lain:
Jenis yang Anda gunakan dalam pencocokan pola sama dengan melewatkan tingkat-jenis alami untuk
takeDef
mengatakan berapa banyak elemen yang harus dilihat.sumber
foo (takeDef -> a:-b:-c:-d:-e:-f:-Nil) -> foobar a b c d e f
sebagai satu baris. Saya tidak menghitung sisanya karena ini adalah kode yang seharusnya ada di perpustakaan, untuk digunakan kembali. Jika harus ditulis hanya untuk kasus ini, itu jelas berlebihan seperti yang Anda katakan.