在我生命中的第三次,我努力学习哈斯克尔,此时通过了解你的Haskell ....
当作者解释警卫时,他展示了这个例子:
bmiTell :: (RealFloat a) => a -> String
bmiTell bmi
| bmi <= 18.5 = "You're underweight, you emo, you!"
| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"
| bmi <= 30.0 = "You're fat! Lose some weight, fatty!"
| otherwise = "You're a whale, congratulations!"
Run Code Online (Sandbox Code Playgroud)
并说
这非常让人联想到命令式语言中的一个很大的if else树,只有这个更好,更易读.虽然大的if else树通常不受欢迎,但有时候问题是以这样一种离散的方式定义的,你无法绕过它们.卫兵是一个非常好的选择.
我可以看到警卫更具可读性,但我不明白为什么语法"好得多"
它更灵活?它更强大?守卫的最大优势是什么?
我的大问题可能是句子
虽然大的if else树通常不受欢迎,但有时候问题是以这样一种离散的方式定义的,你无法绕过它们
任何人都可以举一个例子吗?
C. *_*ann 12
Don给出了使用警卫的主要动机,但除此之外,他们还很好地结合了模式匹配.如果模式上的所有防护装置都失败,它会下降到下一个模式,因此您可以同时检查模式和条件,而不会出现大量重复的坠落情况.这是一个(非常人为的)例子:
expandRange x (Just lo, Just hi) | hi < lo = (Just x, Just x)
expandRange x (Just lo, hi) | x < lo = (Just x, hi)
expandRange x (lo, Just hi) | x > hi = (lo, Just x)
expandRange _ range = range
Run Code Online (Sandbox Code Playgroud)
如果我们认为Nothing是无界,则需要一个元素进行比较,并将负范围"扩展"到仅该元素,移动下限/上限以包含该元素,或者如果已包含该元素则保持范围不变.
现在,考虑如何在不使用警卫的情况下编写上述内容!你最终会复制一个在概念上相同的分支多少次,因为模式不同?是的,我意识到这个小例子可以被重写以完全避免这个问题,但这并不总是可能的(或者是可取的).
在我看来,这种风格的定义是你可以使用守卫表达的最重要的东西,尽管它仍然可能,如果它被写成(无人看守的)模式案例和if表达的混合,那将是非常冗长和更难阅读的.
警卫在语法上更轻松:
相比:
describeLetter c
| c >= 'a' && c <= 'z' = "Lower case"
| c >= 'A' && c <= 'Z' = "Upper case"
| otherwise = "Not an ASCII letter"
Run Code Online (Sandbox Code Playgroud)
有:
describeLetter c =
if c >= 'a' && c <= 'z'
then "Lower case"
else if c >= 'A' && c <= 'Z'
then "Upper case"
else "Not an ASCII letter"
Run Code Online (Sandbox Code Playgroud)
规则部分在语法上更清晰,更易于维护.
此外,它们与视图模式组合良好,以产生令人愉悦的语法.
f x | Just t <- bar x = Right (f t)
| otherwise = Left "some error case"
Run Code Online (Sandbox Code Playgroud)
例如.