卫兵与if-then-else与Haskell中的案件 [英] Guards vs. if-then-else vs. cases in Haskell

查看:113
本文介绍了卫兵与if-then-else与Haskell中的案件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有三个函数可以找到列表的第n个元素:

I have three functions that find the nth element of a list:

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)

在我看来,第一个功能是最好的实现,因为它是最简洁的.但是,是否有其他两种实现方式可以使它们更可取呢?通过扩展,您将如何在使用防护,if-then-else语句和大小写之间进行选择?

In my opinion, the first function is the best implementation because it is the most concise. But is there anything about the other two implementations that would make them preferable? And by extension, how would you choose between using guards, if-then-else statements, and cases?

推荐答案

从技术角度讲,这三个版本都是等效的.

From a technical standpoint, all three versions are equivalent.

话虽如此,我对样式的经验法则是,如果您能像英语一样阅读它(将|读为"when",将| otherwise读为"otherwise",将=读为"is")或是"),则可能是您在做正确的事.

That being said, my rule of thumb for styles is that if you can read it as if it was English (read | as "when", | otherwise as "otherwise" and = as "is" or "be"), you're probably doing something right.

if..then..else适用于您具有一个二进制条件或您需要做出的单个决定.嵌套的if..then..else表达式在Haskell中很少见,应该几乎总是使用警卫代替.

if..then..else is for when you have one binary condition, or one single decision you need to make. Nested if..then..else-expressions are very uncommon in Haskell, and guards should almost always be used instead.

let absOfN =
  if n < 0 -- Single binary expression
  then -n
  else  n

如果每个if..then..else表达式都位于函数的顶层,则可以将其替换为后卫,并且通常应优先使用它,因为这样您可以更轻松地添加更多的案例:

Every if..then..else expression can be replaced by a guard if it is at the top level of a function, and this should generally be preferred, since you can add more cases more easily then:

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

case..of适用于具有多个代码路径的情况,并且每个代码路径均由 值的结构,即通过模式匹配.您很少在TrueFalse上匹配.

case..of is for when you have multiple code paths, and every code path is guided by the structure of a value, i.e. via pattern matching. You very seldom match on True and False.

case mapping of
  Constant v -> const v
  Function f -> map f

Guards补充了case..of表达式,这意味着如果您需要根据值做出复杂的决定,则 first 会根据输入的结构做出决定,然后然后对结构中的值进行决策.

Guards complement case..of expressions, meaning that if you need to make complicated decisions depending on a value, first make decisions depending on the structure of your input, and then make decisions on the values in the structure.

handle  ExitSuccess = return ()
handle (ExitFailure code)
  | code < 0  = putStrLn . ("internal error " ++) . show . abs $ code
  | otherwise = putStrLn . ("user error " ++)     . show       $ code

顺便说一句.作为样式提示,如果=/|之后的内容对于一行而言太长,请始终在=之后或|之前换行. ,或由于其他原因使用更多行:

BTW. As a style tip, always make a newline after a = or before a | if the stuff after the =/| is too long for one line, or uses more lines for some other reason:

-- 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)

这篇关于卫兵与if-then-else与Haskell中的案件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆