在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..elseexpression式都可以被一个守护if..then..else替代,如果它在一个函数的顶层,那么这个应该是首选的,因为你可以更容易地添加更多的情况:

 abs n | n < 0 = -n | otherwise = n 

case..of是当你有多个代码path ,每个代码path是由一个值的结构 ,即通过模式匹配。 你很less匹配TrueFalse

 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也应该有“最后的手段案件”,以防万一你错过了任何东西。