我刚刚开始使用Haskell,但是从我发现的所有在线教程中我似乎无法找到是否有一种可接受的方法来执行条件控制语句。我已经看过if-else,guards和pattern matching,但它们似乎都完成了同样的事情。是否有一种普遍接受/更快/更有效的方式?
答案 0 :(得分:11)
是否有一种普遍接受/更快/更有效的方式?
警卫是(相当复杂的)if-then-else跟随模式匹配的语法糖。 If-then-else是case
超过Bool
的语法糖。所以这些事情大多同样有效。
但是这里有一个观察结果:使用布尔表达式效率通常很容易做效率与模式匹配。开始使用Haskell程序员的最好例子是编写
length xs == 0
其成本与xs
的长度成正比,其中
case xs of { [] -> True; _:_ -> False }
花费不变的时间。
更准确地观察正在发生的事情是(没有像视图模式那样花哨的扩展),模式匹配的最坏情况成本与左侧出现的构造函数的数量成正比 - 你可以写一个既昂贵又小的模式匹配。相比之下,布尔表达式的大小告诉您 nothing 关于评估它的成本。从这个意义上讲,仅从这个意义上讲,模式匹配比if-then-else或guards便宜。
初学者的一个好的启发式方法是尽可能使用模式匹配。随着您获得更多经验,您可以改进您的方法。
答案 1 :(得分:4)
好吧,我不知道用“控制语句”来思考是否是在Haskell中实现它的最好方法。也就是说,最重要的是最终归结为模式匹配;例如,if ... then ... else
等布尔条件可以根据Bool
的构造函数的模式匹配来定义。
最“原始”的形式可能是case
语句 - 函数定义的模式匹配只是包含一个大case
表达式的单个函数定义的语法糖。
就你应该使用什么而言,选择概念上最有意义的东西。当您需要拆分代数数据类型时,模式匹配最合适; if
块适用于某些谓词需要简单的是/否结果时。当您需要数据类型解构和布尔谓词的混合时,通常使用防护。
要记住的最重要的一点是模式匹配是拆分代数数据类型的唯一方法。布尔谓词可以很容易replaced with higher-order functions,但是在数据构造函数中提取值需要模式匹配。
答案 2 :(得分:4)
这三个选项中没有一个完全相同或可以在所有情况下使用。
模式匹配检查使用哪个构造函数创建给定值并绑定变量。既不是守卫也不这样做。如果匹配实现Eq的类型的无效构造函数(或数字文字),则只能使用它们而不是模式匹配。
示例:
foo (Just x) = x+1 -- Can not do this without a pattern match (except by using
-- functions like fromJust that themselves use pattern matches)
foo Nothing = 0 -- You could do this using a pattern guards like
-- foo x | x==Nothing = 0, but that is less readable and less
-- concise than using a plain pattern match
模式保护允许您检查除了相等之外的其他内容。例如。您可以检查给定数字是否大于零。当然你可以用if做同样的事情,但是模式保护可以让你在守卫失败时进入下一个模式,这可以比使用if更少重复。例如:
maybeSqrt (Just x) | x >= 0 = sqrt x
maybeSqrt _ = Nothing
使用if看起来像这样(注意Nothing的重复):
maybeSqrt (Just x) = if x >= 0 then sqrt x
else Nothing
maybeSqrt _ = Nothing
最后如果没有模式匹配就可以使用。如果你实际上没有在给定的值上使用模式匹配来引入case x of ...
,那么你可以使用模式保护毫无意义,并且比仅使用if更不易读和简洁。
答案 3 :(得分:2)
我根据使代码看起来更漂亮和更容易阅读的原因来选择。正如@Don指出的那样,许多这些不同的形式被编译为case
。由于可用的语法糖,它们看起来不同。这种糖不适用于编译器,而是适用于人类。因此,根据您认为其他人想要阅读的内容以及您可以阅读的内容来决定。