在Haskell中,卫兵与if-then-else对比
我有三个函数可以find列表的第n个元素:
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)
在我看来,第一个function是最好的实现,因为它是最简洁的。 但是有没有其他两个实现可以使它们更好? 而且通过扩展,你将如何select使用警卫,if-then-else语句和case?
从技术angular度来看,所有三个版本都是相同的。
这就是说,对于风格来说,我的经验法则是,如果你可以像阅读英文一样来阅读(阅读|
“when”, | otherwise
为“otherwise”和=
as“is”或“be”可能做正确的事情。
if..then..else
则是当你有一个二元条件时 ,或者你需要做出一个单一的决定。 嵌套如果if..then..else
..这些if..then..else
在Haskell中是非常罕见的,应该几乎总是使用守卫。
let absOfN = if n < 0 -- Single binary expression then -n else n
每一个if..then..else
expression式都可以被一个守护if..then..else
替代,如果它在一个函数的顶层,那么这个应该是首选的,因为你可以更容易地添加更多的情况:
abs n | n < 0 = -n | otherwise = n
case..of
是当你有多个代码path ,每个代码path是由一个值的结构 ,即通过模式匹配。 你很less匹配True
和False
。
case mapping of Constant v -> const v Function f -> map f
守卫是expression式的补充,意思是说,如果你需要根据价值做出复杂的决定, 首先根据你input的结构做出决定, 然后决定结构中的值。
handle ExitSuccess = return () handle (ExitFailure code) | code < 0 = putStrLn . ("internal error " ++) . show . abs $ code | otherwise = putStrLn . ("user error " ++) . show $ code
BTW。 作为一个样式提示,在a之后或者在|
之前总是做一个换行符 如果之后的东西是=
/ |
对于一条线太长,或者因为其他原因而使用更多的线:
-- NO! nthElement (x:xs) a | a <= 0 = Nothing | a == 1 = Just x | a > 1 = nthElement xs (a-1) -- Much more compact! Look at those spaces we didn't waste! nthElement (x:xs) a | a <= 0 = Nothing | a == 1 = Just x | otherwise = nthElement xs (a-1)
我知道这是关于显式recursion函数风格的问题,但我build议最好的风格是find一种方法来重用现有的recursion函数。
nthElement xs n = guard (n > 0) >> listToMaybe (drop (n-1) xs)
这只是一个有序的问题,但我认为它的可读性和警卫结构相同。
nthElement :: [a] -> Int -> Maybe a nthElement [] a = Nothing nthElement (x:xs) a = if a < 1 then Nothing else if a == 1 then Just x else nthElement xs (a-1)
最后一个不需要,如果因为没有其他的可能性,function也应该有“最后的手段案件”,以防万一你错过了任何东西。