Haskell模式匹配 - 它是什么?

Ton*_*ion 39 haskell functional-programming pattern-matching

Haskell中的模式匹配是什么?它与保护方程有什么关系?

我试过寻找一个简单的解释,但我还没找到.

编辑:有人标记为家庭作业.我不再去上学了,我只是在学习Haskell,而我正在努力理解这个概念.纯粹出于兴趣.

out*_*tis 63

简而言之,模式就像在数学中定义分段函数一样.您可以使用模式为不同的参数指定不同的函数体.调用函数时,通过将实际参数与各种参数模式进行比较来选择适当的主体.阅读Haskell的温和介绍以获取更多信息.

相比:

斐波那契序列

与等效的Haskell:

fib 0 = 1
fib 1 = 1
fib n | n >= 2 
      = fib (n-1) + fib (n-2)
Run Code Online (Sandbox Code Playgroud)

请注意" ñ ≥2"中的分段函数成为Haskell的版本保护,但其他两个条件只是模式.模式是测试值和结构,如条件x:xs,(x, y, z)Just x.在分段定义中,基于=?关系的条件(基本上,说"某事物"的条件)成为模式.警卫允许更一般的条件.我们可以重写fib使用警卫:

fib n | n == 0 = 1
      | n == 1 = 1
      | n >= 2 = fib (n-1) + fib (n-2)
Run Code Online (Sandbox Code Playgroud)


Nor*_*sey 25

还有其他好的答案,所以我会给你一个非常技术性的答案.模式匹配的是消除结构代数数据类型:

  • "消除构造"意味着"如何消费或使用价值"

  • 除了一流函数之外,"代数数据类型"是静态类型函数语言(如Clean,F#,Haskell或ML)的重要思想.

代数数据类型的想法是你定义一种事物,然后你说出你可以做出的所有方法.例如,让我们将"字符串序列"定义为代数数据类型,有三种方法可以实现:

data StringSeq = Empty                    -- the empty sequence
               | Cat StringSeq StringSeq  -- two sequences in succession
               | Single String            -- a sequence holding a single element
Run Code Online (Sandbox Code Playgroud)

现在,这个定义有各种各样的错误,但作为一个例子,它很有趣,因为它提供了任意长度序列的恒定时间连接.(还有其他的方法来实现这一点.)的声明引入Empty,CatSingle,它们都是有的方式制备序列.(这使得每一个都成为一种介绍构造 - 一种制作东西的方法.)

  • 您可以创建一个没有任何其他值的空序列.
  • 要制作序列Cat,您需要另外两个序列.
  • 要创建序列Single,需要一个元素(在本例中为字符串)

这里有一个妙语:消除构造,模式匹配,为您提供一种方法来仔细检查序列并询问它是什么构造函数?.因为您必须为任何答案做好准备,所以您为每个构造函数提供至少一个替代方案.这是一个长度函数:

slen :: StringSeq -> Int
slen s = case s of Empty -> 0
                   Cat s s' -> slen s + slen s'
                   Single _ -> 1
Run Code Online (Sandbox Code Playgroud)

在语言的核心,所有模式匹配都建立在这个case结构上.但是,由于代数数据类型和模式匹配对于语言的习语非常重要,因此在函数定义的声明形式中进行模式匹配时会有特殊的"语法糖":

slen Empty = 0
slen (Cat s s') = slen s + slen s'
slen (Single _) = 1
Run Code Online (Sandbox Code Playgroud)

使用这种语法糖,通过模式匹配计算看起来很像通过方程定义.(Haskell委员会是故意这样做的.)正如你在其他答案中所看到的那样,case通过在其上打一个警卫,可以将表达式或表达式中的替代方法专门化.我不能想到序列示例的合理守护,其他答案中有很多例子,所以我会留在那里.


C. *_*ann 12

至少在Haskell中,模式匹配与代数数据类型的概念密切相关.当您声明这样的数据类型时:

data SomeData = Foo Int Int
              | Bar String
              | Baz
Run Code Online (Sandbox Code Playgroud)

...它定义Foo,BarBaz作为构造函数 -不要与OOP中的"构造函数"混淆 - 用SomeData其他值构造一个值.

模式匹配只不过是反过来 -一个模式会将一个SomeData值"解构" 成它的组成部分(事实上,我相信模式匹配是在Haskell中提取值的唯一方法).

当一个类型有多个构造函数时,你为每个模式编写一个函数的多个版本,根据使用的构造函数选择正确的函数(假设你已经编写了匹配所有可能结构的模式 - 这通常是好的做练习).