在哪种感觉守卫比命令更好 - 如果?(haskell新手)

Pab*_*afi 7 haskell

在我生命中的第三次,我努力学习哈斯克尔,此时通过了解你的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表达的混合,那将是非常冗长和更难阅读的.

  • @PabloGrisafi:而且,"只是更具可读性",不能掉以轻心!同时简洁,可读和富有表现力的是高级语言的价值所在 - 这三者都是绝对必要的. (2认同)

Don*_*art 7

警卫在语法上更轻松:

  • 许多不同的案例
  • 嵌套案例

相比:

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)

例如.