模式匹配

在計算機科學中，模式匹配是檢查給定記號序列中，是否存在某種模式的組成部分的行為。與模式識別相反，匹配通常必須是精確的。模式通常具有序列或樹狀結構的形式。模式匹配的用途包括：輸出一個模式在一個記號序列中的位置（如果有的話），輸出匹配模式的一些組成部份，以及用一些其他的記號序列替換匹配模式（即搜索和替換）。

**概述**
在一些編程語言中，模式被用作一種通用工具，基於數據的結構來處理數據，包括C#、 F#、Haskell、ML、Python、Ruby、Rust、Scala、Swift、倉頡和Mathematica的符號式Wolfram語言，它們擁有表達樹狀結構的特殊語法，和基於它的條件執行和值檢索的Language construct。
經常可以給出逐個嘗試的交替式模式，它產生強力的條件編程構造fib (0) fib (1) fib (n+2) Darlington got this idea from Kleene’s recursion equations.|access-date=2022-02-18|archive-date=2020-04-15|archive-url=https://web.archive.org/web/20200415053847/https://www.cs.kent.ac.uk/people/staff/dat/tfp12/tfp12.pdf。模式匹配有時包括對守衛子句的支持sign x = 1, if x>0= -1, if x= 0, if x=0Combining pattern matching with guards gives a significant gain in expressive power. Guards of this kind first appeared in KRC, “Kent Recursive Calculator”(Turner 1981, 1982), a miniaturised version of SASL which I designed in 1980–81 for teaching.|access-date=2022-02-18|archive-date=2020-04-15|archive-url=https://web.archive.org/web/20200415053847/https://www.cs.kent.ac.uk/people/staff/dat/tfp12/tfp12.pdf。
字符序列也就是字符串，經常使用正則表達式來描述，並使用像回溯這樣的技術來進行匹配。解析算法經常依賴模式匹配來將字符串變換成語法樹。

**歷史**
具有模式匹配構造的早期編程語言包括：COMIT（1957年）、SNOBOL（1962年）、具有樹狀模式的Refal（1968年）、Prolog（1972年）、SASL（1976年）、NPL（1977年）和KRC（1981年）。
很多文本編輯器支持各種的模式匹配：支持正則表達式查找的QED編輯器，和在查找中支持OR運算的某些版本的TECO。計算機代數系統一般支持在代數表達式上的模式匹配。

**簡單模式**
在模式匹配中，最簡單的模式是一個明確的值或一個變量。例如，考慮採用Haskell語法的一個簡單函數，這裡函數參數不放在圓括號內但用空白分隔，=不是賦值而是定義：
f 0 = 1
這裡的0是一個單一值模式。只要f被給予0作為參數，這個模式就匹配，並且函數返回1。對於任何其他參數，匹配失敗，因而這個函數也失敗。因為在函數定義中，語法上支持交替式模式，可以繼續將定義擴展為接受更一般性的參數：
f n = n * f (n-1)
這裡的第一個n是單一變量模式，它絕對的匹配任何參數，並將它綁定到名字n，而用在定義的餘下部份之中。在Haskell中（至少不似Hope），模式被依次嘗試，所以第一個定義仍適用於輸入是0的非常特殊情況，而對於任何其他參數，函數返回n * f (n-1)，具有n是為參數。
通配符模式（通常寫為_）也是簡單的：就像一個變量名字，它匹配任何值，但是不把這個值綁定到任何名字。在簡單字符串匹配情況下的Matching wildcards算法，已經發展出很多遞歸和非遞歸的變體。
在Haskell中，下面的代碼定義了一個代數數據類型Color，它有一個單一的數據構造子ColorConstructor，包裝一個整數和一個字符串：
data Color = ColorConstructor Integer String
例如，要得到Color類型的整數部份的一個函數可以寫為：
integerPart (ColorConstructor theInteger _) = theInteger
要得到字符串部份：
stringPart (ColorConstructor _ theString) = theString
這些函數可以通過Haskell的數據記錄語法自動創建。
模式匹配還可應用來過濾特定結構的數據。例如，在Haskell中可以使用列表推導式進行這種過濾：
data ABint = A Int | B Int
A x|A x 
求值結果為：
A 1, A 2

**序列模式**
從上述原始模式，可以建造更加複雜的模式，通常採用的方式，相同於通過組合其他值來建造值。區別在於，具有變量和通配符部份，模式不建造成一個單一值，而是匹配一組值，它們是具體元素和允許在模式結構內變化的元素的組合。
在Haskell和一般的函數式編程語言中，列表是主要數據結構，它通常被定義為一種典型的代數數據類型：
data List a = Nil | Cons a (List a)
Cons是構造（construct）的簡寫。很多語言針對以這種方式定義的列表提供特殊語法。例如，Haskell和ML，分別將用於Nil，:或::用於Cons，並將方括號用於整個列表。所以"haskell"通常在Haskell中寫為"haskell"或code|1,2,3|"haskell"，在OCaml中寫為"sml"或code|1;2;3|"sml"。
列表被定義為空列表，或一個元素構造在一個現存的列表上。在Haskell語法下寫為：
-- 空列表
x:xs -- 元素x構造在列表xs之上
具有一些元素的一個列表的結構，就是element:list。在模式匹配的時候，斷定特定部份的數據等於特定模式。例如，在如下函數中：
head (element:list) = element
這裡斷定了head的實際參數的第一個元素被稱為element，並且這個函數返回這個元素。之所以知道它是第一個元素的，是因為列表的定義方式，它是一個單一元素構造在一個列表之上，這個單一元素必定是第一個元素。空列表根本不匹配這個模式，因為空列表沒有頭部（要構造的第一個元素）。
在這個例子中，我們沒有用到list，可以漠視它，而將函數寫為：
head (element:_) = element

**樹狀模式**
樹狀模式一般用來匹配由遞歸數據類型生成的複雜的樹狀結構，比如編程語言抽象語法樹。它通過開始於一個節點，指定某些分支以及節點，並且通過變量或通配符留下一些不指定，來描述一個樹的一部份。
下面是在OCaml下，定義一個紅黑樹和在元素插入後再平衡的函數的例子：
type color = Red | Black
type 'a tree = Empty | Tree of color * 'a tree * 'a * 'a tree
let rebalance t = match t with

Tree (Black, Tree (Red, Tree (Red, a, x, b), y, c), z, d)

Tree (Black, Tree (Red, a, x, Tree (Red, b, y, c)), z, d)                                  

Tree (Black, a, x, Tree (Red, Tree (Red, b, y, c), z, d))

Tree (Black, a, x, Tree (Red, b, y, Tree (Red, c, z, d)))
->  Tree (Red, Tree (Black, a, x, b), y, Tree (Black, c, z, d))

_ -> t (* the 'catch-all' case if no previous pattern matches *)

**字符串模式**
迄今最常用形式的模式匹配涉及字符串。在很多編程語言中，使用特定的字符串語法來表示正則表達式，它是描述字符串的模式。
在Haskell中，如下模式匹配有兩個字符並且開始於'a'的字符串:
'a', _
可以介入符號式實體，來表示一個字符串的很多不同類的有關特徵。在Haskell中，可以使用守衛來進行匹配：
letter, digit | isAlpha letter && isDigit digit
它將匹配首個字符是一個字母，接著的是一個數字的字符串。
符號式字符串操縱的主要好處，是它可以與編程語言的其餘部份完全的集成，而非成為一個獨立的、專用的子單元。這個語言的整體能力，可以放大到建造模式自身，或分析和變換包含它們的程序。

**Python的模式匹配**

**定義**
在Python版本3.10中，模式匹配的語法應該是：
match subject:
case :

case :

case :

case _:

其中 subject表示原始數據，表示不同模式，_表示通配符，如果在上文中沒有找到精確匹配的對象，將會使用通配符。如果一個模式匹配沒有精確匹配上且沒有通配符，整個語句不做任何作用（no-op）。

**例子**
在Python版本3.10中：
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:         #省略此行及下一行以創造一個沒有通配符的模式匹配
return "Something's wrong with the Internet"
如果省略最後兩行，當status為500時什麼都不會發生。
同理，模式匹配也可用於class中：
class Point:
x: int
y: int
def location(point):
match point:
case Point(x=0, y=0):
print("Origin is the point's location.")
case Point(x=0, y=y):
print(f"Y={y} and the point is on the y-axis.")
case Point(x=x, y=0):
print(f"X={x} and the point is on the x-axis.")
case Point():
print("The point is located somewhere else on the plane.")
case _:
print("Not a point")
和其他語言中的模式匹配一樣，Python中也可以在匹配的語句中使用通配符：
match test_variable:
case ('warning', code, 40):
print("A warning has been received.")
case ('error', code, _):
print(f"An error {code} occurred.")

**引用**

**外部鏈接**
 Nikolaas N. Oosterhof, Philip K. F. Hölzenspies, and Jan Kuper.  Application patterns. A presentation at Trends in Functional Programming, 2005- JMatch date=20220513111350 : the Java programming language extended with pattern matching- ShowTrend: Online pattern matching for stock prices- An incomplete history of the QED Text Editor by Dennis Ritchie - provides the history of regular expressions in computer programs- The Implementation of Functional Programming Languages, pages 53–103 date=20081207050942  Simon Peyton Jones, published by Prentice Hall, 1987.- Nemerle, pattern matching date=20220218075200 .- Erlang, pattern matching date=20220622050029 .- Prop: a C++ based pattern matching language, 1999- PatMat: a C++ pattern matching library based on date=20220316023532  SNOBOL/SPITBOL- Temur Kutsia.  Flat Matching. Journal of Symbolic Computation 43(12): 858–873. Describes in details flat matching in Mathematica.- EasyPattern language date=20210413231658  pattern matching language for non-programmers