守卫与之相反,与哈斯克尔的情况相反(Guards vs. if

编程入门 行业动态 更新时间:2024-10-28 14:25:06
守卫与之相反,与哈斯克尔的情况相反(Guards vs. if-then-else vs. cases in Haskell)

我有三个函数可以找到列表的第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)

在我看来,第一个功能是最好的实现,因为它是最简洁的。 但是有什么可以让其他两个实现呢? 而延期,你如何选择使用守卫,if-then-else语句和案例?

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)

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?

最满意答案

从技术角度来看,所有三个版本都是等效的。

就是说,我的风格经验是,如果你可以读它,就好像是英文(看作| “当”, | otherwise为“否则”, = “是”或“是”),可能正在做一些正确的事情

if..then..else是当你有一个二进制条件 ,或一个单一的决定,你需要做。 嵌套if..then..else表达式在Haskell中非常罕见,几乎总是使用守卫。

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

每个if..then..else表达式都可以被一个if..then..else替换,如果它在一个函数的顶层,这通常是首选的,因为你可以更容易地添加更多的案例:

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

case..of是当您有多个代码路径时 ,每个代码路径都由一个值的结构引导,即通过模式匹配。 你真的很少匹配False 。

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

守卫补充表达式,意味着如果您需要根据值做出复杂的决定, 首先根据输入的结构做出决定, 然后对结构中的值进行决策。

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)

From a technical standpoint, all three versions are equivalent.

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

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

更多推荐

本文发布于:2023-07-16 12:30:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1128508.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:与之   斯克   情况   Guards

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!