haskell - 模式匹配和守卫有什么区别?

标签 haskell syntax guard

我对 Haskell 和一般的函数式编程非常陌生。我的问题很基本。模式匹配和守卫有什么区别?

使用模式匹配的函数

check :: [a] -> String
check [] = "Empty"
check (x:xs) = "Contains Elements"

使用守卫的函数

check_ :: [a] -> String
check_ lst
    | length lst < 1 = "Empty"
    | otherwise = "Contains elements"

对我来说,模式匹配和守卫本质上是相同的。两者都评估一个条件,如果为 true 将执行与其 Hook 的表达式。我的理解正确吗?

在此示例中,我可以使用模式匹配或防护来获得相同的结果。但有件事告诉我,我在这里错过了一些重要的事情。我们可以随时替换其中一个吗?

有人可以举例说明模式匹配优于守卫,反之亦然吗?

最佳答案

事实上,它们本质上是完全不同的!至少在 Haskell 中是这样。

守卫既简单又灵活:它们本质上只是转换为一系列 if/then 表达式的特殊语法。您可以在防护中放置任意 bool 表达式,但它们不会执行常规 if 无法执行的任何操作。

模式匹配还可以做一些额外的事情:它们是解构数据的唯一方法,并且它们在其范围内绑定(bind)标识符。正如守卫相当于 if 表达式一样,模式匹配也相当于 case 表达式。声明(无论是在顶层,还是在类似 let 表达式中)也是模式匹配的一种形式,“正常”定义与简单模式(单个标识符)匹配。

模式匹配也往往是 Haskell 中实际发生的主要方式——尝试解构模式中的数据是强制评估的少数事情之一。

顺便说一句,您实际上可以在顶级声明中进行模式匹配:

square = (^2)

(one:four:nine:_) = map square [1..]

这有时对于一组相关定义很有用。

GHC 也是 provides the ViewPatterns extension,它结合了两者;您可以在绑定(bind)上下文中使用任意函数,然后对结果进行模式匹配。当然,这仍然只是普通内容的语法糖。

<小时/>

至于在哪里使用哪个的日常问题,这里有一些粗略的指南:

  • 对于任何可以直接深度匹配一两个构造函数的内容,绝对使用模式匹配,在这种情况下,您并不真正关心整个复合数据,但确实关心大部分结构。 @ 语法允许您将整体结构绑定(bind)到变量,同时还可以对其进行模式匹配,但是在一个模式中执行太多操作可能会很快变得丑陋且不可读。

  • 当您需要根据某些与模式不完全对应的属性(例如比较两个 Int 值,看看哪个更大。

  • 如果您只需要大型结构内部深处的几条数据,特别是如果您还需要使用整个结构,则防护和访问器函数通常比一些充满 @ 的可怕模式更具可读性和_

  • 如果您需要对不同模式表示的值执行相同的操作,但需要使用方便的谓词对它们进行分类,那么使用带有保护的单个通用模式通常更具可读性。请注意,如果一组防护措施不是详尽无遗的,则所有未能通过所有防护措施的任何内容都将下降到下一个模式(如果有)。因此,您可以将一般模式与某些过滤器结合起来以捕获异常情况,然后对其他所有内容进行模式匹配以获得您关心的详细信息。

  • 绝对不要对那些可以用模式简单检查的东西使用防护。检查空列表是典型的示例,为此使用模式匹配。

  • 一般来说,当有疑问时,只需坚持默认的模式匹配,通常会更好。如果一个模式开始变得非常丑陋或令人费解,那么就停下来考虑一下你还能如何编写它。除了使用保护之外,其他选项还包括将子表达式提取为单独的函数,或者将 case 表达式放入函数体内,以便将一些模式匹配向下推到它们上面并移出主定义。

关于haskell - 模式匹配和守卫有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4156727/

相关文章:

perl - 我应该使用 Perl 的条件吗? : operator as a switch/case statement or instead of if elsif?

ruby-on-rails - RoR 中的 Spring 服务器的功能是什么?

ruby-on-rails - RubyMine 不能使用 Guard 吗?

haskell - 如何在没有缩进树的情况下处理嵌套的 case 语句?

haskell - 如何将命令行参数传递给 stack exec

c++ - 可变参数宏的 2 种不同语法

Java 三元运算符语法

ruby-on-rails - 部署时的 bundle 程序错误

haskell - "symmetric"函数的模式

haskell - 使用 de Bruijn 索引将 Data.Reify 显式共享图转换为 AST