Haskell 在哪种意义上,警卫比命令式警卫更好?(哈斯克尔新成员)
这是我一生中第三次尝试学习哈斯克尔,这次是通过。Haskell 在哪种意义上,警卫比命令式警卫更好?(哈斯克尔新成员),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 <= 3
当作者解释警卫时,他展示了这个例子:
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!"
bmiTell::(RealFloat a)=>a->String
体重指数
|bmi防护装置在语法上较轻,适用于:
- 许多不同的情况
- 嵌套案例
比较:
describeLetter c
| c >= 'a' && c <= 'z' = "Lower case"
| c >= 'A' && c <= 'Z' = "Upper case"
| otherwise = "Not an ASCII letter"
bmiTell bmi
| bmi <= 18.5 = "................................."
| bmi <= 25.0 = "..........................................."
| bmi <= 30.0 = "...................................."
| otherwise = "................................"
bmiTell bmi =
if bmi <= 18.5 then "................................."
else if bmi <= 25.0 then "..........................................."
else if bmi <= 30.0 then "...................................."
else "................................"
描述符c
|c>='a'&&c='a'&&c='a'&&c='a'&&c如果周围有很多if,任何问题都可以被形象化为决策图。您引用的LYAH示例的决策图如下:
.
/ \
/ \
/bmi? \
\ /
\ /
/ \ / \
/ / \ \
/ | | \
/ | | \
/ | | \
/ | | \
< 18.5 /18.5-25| | 25-30 \ > 30
/ | | \
... ... ... ...
。
/ \
/ \
/体重指数\
\ /
\ /
/ \ / \
/ / \ \
/ | | \
/ | | \
/ | | \
/ | | \
< 18.5 /18.5-25| | 25-30 \ > 30
/ | | \
... ... ... ...
guards的最大优点是,它们让语法结构反映决策图的结构。如果您只有If-then-else,那么您必须使用一系列嵌套的If来实现上述决策图,即用两个分支选择的级联来编码多分支选择。嵌套的if会模糊算法的高层思想
现在,我认为LYAH的作者在你引用的那句话中的意思是,有时候你不能用守卫做得比用嵌套的if-then-else做得更好。但只有当选择相互依赖时才是如此,即当决策图包含许多菱形框(选择),每个框只有两个分支,并且不能以任何其他方式重写时。请注意,在bmiTell
示例中,每个分支相互独立,因为BMI只能归入4个类别,其中任何一个类别都不重叠。Don给出了使用防护的主要动机,但除此之外,它们还与模式匹配很好地结合在一起。如果一个模式上的所有防护都失败,它将进入下一个模式,因此您可以同时检查模式和条件,而不必有大量重复的失败案例。下面是一个(非常人为的)例子:
expandRange x(刚好低,刚好高)| hihi=(lo,Just x)
expandRange uRange=范围
如果我们认为Nothing
是无界的,则需要对元素进行比较,或者将负范围“扩展”到仅该元素,移动下限/上限以包含该元素,或者如果元素已包含,则保持范围不变
现在,考虑一下如何在不使用警卫的情况下编写上面的代码!由于模式不同,您会重复多少次概念上相同的分支?是的,我意识到这个小例子可以重写以完全避免这个问题,但这并不总是可能的(或可取的)
在我看来,这种定义风格是你可以用防护来表达的最重要的东西,尽管仍然可能,但如果它是混合(无防护)的话,它会更加冗长,更难阅读模式案例和if
表达式。防护装置在视觉上更加明显,不太冗长⁄其“噪音”更少
比较:
describeLetter c
| c >= 'a' && c <= 'z' = "Lower case"
| c >= 'A' && c <= 'Z' = "Upper case"
| otherwise = "Not an ASCII letter"
bmiTell bmi
| bmi <= 18.5 = "................................."
| bmi <= 25.0 = "..........................................."
| bmi <= 30.0 = "...................................."
| otherwise = "................................"
bmiTell bmi =
if bmi <= 18.5 then "................................."
else if bmi <= 25.0 then "..........................................."
else if bmi <= 30.0 then "...................................."
else "................................"
bmi
|bmi除了更具可读性之外,并没有添加任何内容。@KarolisJuodelė:他们确实添加了一些东西:图案保护,这不能用简单的if
那么else
–也不能用的case
,但只能用两者的组合。尽管增加缩进是不必要的。您可以将其垂直对齐。Right(ft)
中的f
是否正确?看起来你会有一个无限递归类型。但请注意:这不是惯用的Haskell。@DonStewart,我认为这是主观的。有时你需要一个函数中的一个构造,你不想定义一个单独的函数,这样你就可以用警卫把它写下来。在这种情况下的另一个选项是GHC 7.6中新增的一个。所以我学到了两件事:在大多数情况下,如果是的话,警卫的可读性更高,但当你结合模式匹配时,他们真正的力量就会显现出来。哈斯凯尔对我来说就像一块知识块:你要么把它全部拼凑起来,要么就是不懂。@PabloGrisafi:而且,“更具可读性”一点也不可掉以轻心!同时简洁、可读和富有表现力是高级语言的价值所在——这三者都是绝对必要的。没错,可读性非常重要。我想说的是,除了您展示的模式匹配组合之外,警卫的概念与命令式语言中的if/else几乎相同。哈斯克尔对我的命令式思维方式来说真的很不一样,也很奇怪,但警卫毕竟不是那么陌生。@PabloGrisafi:是的。模式匹配也是如此——两者都不是固有的功能(在某些方面,它们是相反的)。事实上,我有时希望命令式语言包括模式匹配(在代数数据类型上)和保护——它们类似于典型的开关
或大小写
结构,但更有用。
bmiTell bmi
| bmi <= 18.5 = "................................."
| bmi <= 25.0 = "..........................................."
| bmi <= 30.0 = "...................................."
| otherwise = "................................"
bmiTell bmi =
if bmi <= 18.5 then "................................."
else if bmi <= 25.0 then "..........................................."
else if bmi <= 30.0 then "...................................."
else "................................"