Saya memiliki tiga fungsi yang menemukan elemen ke-n dari sebuah daftar:
nthElement :: [a] -> Int -> Maybe a
nthElement [] a = Nothing
nthElement (x:xs) a | a <= 0 = Nothing
| a == 1 = Just x
| a > 1 = nthElement xs (a-1)
nthElementIf :: [a] -> Int -> Maybe a
nthElementIf [] a = Nothing
nthElementIf (x:xs) a = if a <= 1
then if a <= 0
then Nothing
else Just x -- a == 1
else nthElementIf xs (a-1)
nthElementCases :: [a] -> Int -> Maybe a
nthElementCases [] a = Nothing
nthElementCases (x:xs) a = case a <= 0 of
True -> Nothing
False -> case a == 1 of
True -> Just x
False -> nthElementCases xs (a-1)
Menurut saya, fungsi pertama adalah implementasi terbaik karena paling ringkas. Tetapi apakah ada sesuatu tentang dua implementasi lainnya yang akan membuatnya lebih disukai? Dan selanjutnya, bagaimana Anda akan memilih antara menggunakan penjaga, pernyataan if-then-else, dan kasus?
haskell
if-statement
case
nukleartida
sumber
sumber
case
pernyataan bertingkat Anda jika Anda menggunakancase compare a 0 of LT -> ... | EQ -> ... | GT -> ...
case compare a 1 of ...
Jawaban:
Dari sudut pandang teknis, ketiga versi itu setara.
Karena itu, aturan praktis saya untuk gaya adalah jika Anda dapat membacanya seolah-olah itu adalah bahasa Inggris (dibaca
|
sebagai "when",| otherwise
sebagai "else" dan=
sebagai "is" atau "be"), Anda mungkin sedang melakukan sesuatu Baik.if..then..else
adalah saat Anda memiliki satu ketentuan biner , atau satu keputusan tunggal yang perlu Anda buat.if..then..else
Ekspresi- bersarang sangat tidak umum di Haskell, dan sebagai gantinya, pelindung hampir selalu digunakan.Setiap
if..then..else
ekspresi dapat diganti dengan penjaga jika berada di tingkat atas suatu fungsi, dan ini biasanya lebih disukai, karena Anda dapat menambahkan lebih banyak kasus dengan lebih mudah:case..of
adalah ketika Anda memiliki beberapa jalur kode , dan setiap jalur kode dipandu oleh struktur nilai, yaitu melalui pencocokan pola. Anda sangat jarang cocokTrue
danFalse
.Penjaga melengkapi
case..of
ekspresi, artinya jika Anda perlu membuat keputusan yang rumit bergantung pada nilai, pertama - tama buat keputusan berdasarkan struktur masukan Anda, lalu buat keputusan tentang nilai dalam struktur tersebut.BTW. Sebagai tip gaya, selalu buat baris baru setelah a
=
atau sebelum a|
jika barang setelah=
/|
terlalu panjang untuk satu baris, atau gunakan lebih banyak baris untuk beberapa alasan lain:sumber
True
danFalse
" adakah kesempatan di mana Anda akan melakukan itu? Bagaimanapun, keputusan semacam ini selalu bisa dilakukan denganif
, dan dengan penjaga juga.case (foo, bar, baz) of (True, False, False) -> ...
guard
fungsi memerlukanMonadPlus
, tetapi yang kita bicarakan di sini adalah penjaga seperti dalam| test =
klausa, yang tidak terkait.Saya tahu ini adalah pertanyaan tentang gaya untuk fungsi rekursif secara eksplisit, tetapi saya akan menyarankan bahwa gaya terbaik adalah menemukan cara untuk menggunakan kembali fungsi rekursif yang ada.
sumber
Ini hanya masalah pemesanan tapi saya rasa ini sangat mudah dibaca dan memiliki struktur yang sama dengan penjaga.
Yang terakhir tidak perlu dan jika karena tidak ada kemungkinan lain, fungsi juga harus memiliki "kasus pilihan terakhir" jika Anda melewatkan sesuatu.
sumber