2021.5.4

Motoko笔记

模式匹配(Pattern Matching)是一种语言特性,它使结构化数据的测试和分解变得容易。虽然大多数编程语言提供了构建结构化数据的熟悉方法,但模式匹配使您能够分解结构化数据,并通过将它们绑定到指定的名称来将其片段引入范围。在语法上,这些模式类似于结构化数据的构造,但通常出现在输入方向的位置,例如函数参数位置、switch表达式中的case关键字之后以及let或var声明之后。

考虑以下函数调用:

func fullName({ first : Text; mid : Text; last : Text }) : Text { 
	first # " " # mid # " " # last 
};

输入是一个(匿名)对象,它被分解为三个文本字段,其值被绑定到标识符first、mid和last。它们可以在构成函数体的块中自由使用。上面我们对对象字段模式使用了名称双关,它们的一般形式允许绑定标识符与字段名称不同,如mid = middle_name : Text.

您还可以使用模式匹配来搜索文本模式(literal patterns),它看起来就像文本常量。文本模式在switch表达式中特别有用,因为它们会导致当前模式匹配失败,从而开始匹配下一个模式。例如:

switch ("Adrienne", #female) { 
	case (name, #female) { "It's a girl! " # name }; 
	case (name, _) { name # ", a boy!" }; 
}

将匹配第一个case子句(因为绑定到标识符名称不可能失败,并且the shorthand variant literal #Female compares as equal),并计算为“It's a girl!Adrienne”。第二个子句显示通配符模式(wildcard pattern)。它不可能失败,但不会绑定任何标识符。

最后一种模式是or模式。顾名思义,这是两个或两个以上的模式,由关键字or分隔。每个子模式必须绑定到同一组标识符,并且从左到右匹配。或模式在其最右边的子模式失败时失败。

Table 1. The following table summarises the different ways of pattern matching.

pattern kindexamplesappears incan failremarks
literalnull, 42, (), "Hi"everywherewhen the type has more than one value 
namedage, xeverywherenointroduces identifiers into a new scope
wildcard_everywhereno 
typedage : Nateverywheredepends 
option?0, ?valeverywhereyes 
tuple( component0, component1, …​ )everywheredependsmust have at least two components
object{ fieldA; fieldB; …​ }everywheredependsallowed to mention a subset of fields
fieldage, count = 0objectdependsage is short for age = age
variant#celsius deg, #sundayeverywhereyes#sunday is short form for #sunday ()
alternative (or-pattern)0 or 1everywheredependsno alternative may bind an identifier

Additional information about about patterns:

由于模式匹配有着丰富的历史和有趣的机制,一些附加的评论是合理的。

  • nomenclature The (usually structured) expression that is being matched is frequently called the scrutinee and the patterns appearing behind the keyword case are the alternatives. When every possible scutinee is matched by (at least one) alternative, then we say that the scrutinee is covered. The patterns are tried in top-down fashion and thus in case of overlapping patterns the one higher-up is selected. A scrutinee is considered dead (or inactive), if for every value that it matches there is higher-up alternative that is also matched.

“术语匹配的表达式(通常是结构化的)经常被称为scrutinee,出现在关键字case后面的模式是可选的。当每一个可能的scrutinee都与(至少一个)备选方案匹配时,我们就说scrutinee被覆盖了。这些Pattern是以自上而下的方式尝试的,因此在重叠Pattern的情况下,选择较高的一个。scrutinee被认为是死的(或不活动的),如果它匹配的每一个值都有更高的替代值也匹配。”

  • booleans:The data type Bool can be regarded as two disjointed altenatives (true and false) and Motoko’s built-in if construct will eliminate the data and turn it into control flow. if expressions are a form of pattern matching that abbreviates the general switch expression for the special case of boolean scrutinees.

"booleans:数据类型Bool可以看作是两个不相交的交替变量(true和false),Motoko的内置if构造将消除数据并将其转换为控制流。if表达式是一种模式匹配形式,它简化了在特殊情况(boolean scrutinees)下的通用的switch表达"

  • variant patterns:Motoko’s variant types are a form of disjoint union (sometimes also called a sum type). A value of variant type always has exactly one discriminator and a payload which can vary from discriminator to discriminator. When matching a variant pattern with a variant value, the discriminators must be the same (in order to select the alternative) and if so, the payload gets exposed for further matching.

“variant patterns:Motoko的variant types是不相交并集的一种形式(有时也称为一种 sum type)。变量类型的值总是正好有一个鉴别器和一个有效负载,而有效负载在鉴别器之间可能有所不同。在将variant pattern与variant value匹配时,鉴别器必须相同(以便选择备选方案),如果是这样,则有效负载将暴露以进行进一步匹配。”

  • enumerated types:Other programming languages—for example C, but not Motoko—often use a keyword enum to introduce enumerations. These are impoverished relatives of Motoko’s variant types, as the alternatives are not allowed to carry any payload. Correspondingly, in those languages the switch-like statements lack the full power of pattern matching. Motoko provides the short-hand syntax (as in type Weekday = { #mon; #tue; …​ }) to define enumerations, where payload for the variants is not desired.

“枚举类型:其他编程语言(例如C,但不是Motoko)经常使用关键字enum来引入枚举。这些是Motoko变种的贫穷亲戚(???),因为替代品不允许携带任何有效载荷。相应地,在这些语言中,switch-like语句缺乏模式匹配的全部能力。Motoko提供了简写语法(如type Weekday = { #mon; #tue; …​ } ) 定义枚举,其中不需要变量的有效负载。”

  • error handling:Error handling can be considered a use-case for pattern matching. When a function returns a value that has an alternative for success and one for failure (for example, an option value or a variant), pattern matching can be used to distinguish between the two as discussed in Error handling.

“错误处理:错误处理可以被认为是模式匹配的一个用例。当函数返回一个值,其中一个值表示成功,另一个值表示失败(例如,选项值或变量),模式匹配可以用来区分这两个值,如Error handling中所讨论的。”

  • non-failable matching:Some types admit only a single value and we call these singleton types. Examples of these are the unit type (also known as an empty tuple) or tuples that only contain singleton types. Variants with only one alternative and no payload (or singleton-typed payload) are singleton types too. Pattern matching on singleton types is particularly straightforward, as it only has one possible alternative, which can never fail.

“无故障匹配:某些类型只允许一个值,我们称之为单例类型。例如,单元类型(也称为空元组)或仅包含单例类型的元组。只有一个备选方案而没有有效负载(或单例类型的有效负载)的变体也是单例类型。单例类型上的模式匹配特别简单,因为它只有一种可能的选择,这是永远不会失败的。”

  • exhaustiveness (coverage) checking:When a pattern check alternative has the potential to fail, then it becomes important to find out whether the whole switchexpression can fail. If this can happen the execution of the program can trap for certain inputs, posing an operational threat. To this end, the compiler checks for the exhaustiveness of pattern matching by keeping track of the covered shape of the scrutinee. The compiler issues a warning for any non-covered scrutinees (Motoko even tries to come up with an example of a scrutinee that is not patched). As by-product of the exhaustiveness check, warnings are also issued for dead alternatives.

“穷尽性(coverage)检查:当一个模式检查选项有可能失败时,找出整个switch表达式是否会失败就变得非常重要。如果发生这种情况,程序的执行可能会捕获某些输入,从而构成操作威胁。为此,编译器通过跟踪scrutinee的覆盖形状来检查模式匹配的完备性。编译器会对任何未覆盖的scrutinees发出警告(Motoko甚至试图给出一个未修补的scrutinee示例)。作为穷尽性检查的副产品,也会对失效的替代品发出警告。”

总之,模式检查对于一些用例来说是一个很好的工具,它通过指出哪些输入没有被彻底地处理,使得编译器能够主动地帮助程序员。覆盖率检查的静态编译时特性可靠地排除了运行时故障。The static compile-time nature of coverage checking reliably rules out runtime failures.


A Student on the way to full stack of Web3.