【发布时间】:2010-09-17 00:39:50
【问题描述】:
我一直试图向几个人解释 switch 语句和模式匹配 (F#) 之间的区别,但我真的无法很好地解释它..大多数时候他们只是看着我说“那你为什么不直接使用 if..then..else”。
你会如何向他们解释?
编辑!谢谢大家的好答案,我真的希望我能标记多个正确的答案。
【问题讨论】:
标签: f# pattern-matching ocaml sml
我一直试图向几个人解释 switch 语句和模式匹配 (F#) 之间的区别,但我真的无法很好地解释它..大多数时候他们只是看着我说“那你为什么不直接使用 if..then..else”。
你会如何向他们解释?
编辑!谢谢大家的好答案,我真的希望我能标记多个正确的答案。
【问题讨论】:
标签: f# pattern-matching ocaml sml
也许你可以用字符串和正则表达式来类比?您描述您要查找的什么,然后让编译器自己找出如何。它使您的代码更简单、更清晰。
顺便说一句:我发现模式匹配最有用的地方在于它鼓励了良好的习惯。我首先处理极端案例,很容易检查我是否涵盖了所有案例。
【讨论】:
【讨论】:
在我的头顶:
【讨论】:
模式为您提供了一种小语言来描述您想要匹配的值的结构。结构可以任意深,您可以将变量绑定到结构化值的某些部分。
这使您可以非常简洁地编写内容。你可以用一个小例子来说明这一点,比如简单类型数学表达式的导函数:
type expr =
| Int of int
| Var of string
| Add of expr * expr
| Mul of expr * expr;;
let rec d(f, x) =
match f with
| Var y when x=y -> Int 1
| Int _ | Var _ -> Int 0
| Add(f, g) -> Add(d(f, x), d(g, x))
| Mul(f, g) -> Add(Mul(f, d(g, x)), Mul(g, d(f, x)));;
此外,由于模式匹配是静态类型的静态构造,编译器可以 (i) 验证您是否涵盖了所有情况 (ii) 检测永远无法匹配任何值的冗余分支 (iii) 提供非常有效的实现(使用跳跃等)。
【讨论】:
Add of expr * expr 我想你是想写+
+ 无效,* 不应被解释为算术乘法。 Add of expr * expr 声明了一个非常量构造函数 Add,其 2 个参数的类型均为 expr。因此,您可以使用它来构造 2 个标记为 Add 的表达式的组合。
开关是两个前轮。
模式匹配是整辆车。
【讨论】:
模式匹配比 switch 语句和方法调度有几个优点:
【讨论】:
OCaml 中的模式匹配,除了在上面描述的几种方式中提到的更具表现力之外,还提供了一些非常重要的静态保证。编译器将为您证明您的模式匹配语句所体现的案例分析是:
这真是一件大事。当您第一次编写程序时它很有帮助,并且在您的程序不断发展时非常有用。如果使用得当,匹配语句可以更轻松地可靠地更改代码中的类型,因为类型系统会将您指向损坏的匹配语句,这是您需要修复的代码的良好指标。
【讨论】:
元组有“,”,变体有 Ctor args .. 这些是构造函数,它们创造事物。
模式是析构函数,它们将它们撕裂。
它们是双重概念。
更强有力地说:元组或变体的概念不能仅仅由它的构造函数来描述:析构函数是必需的,或者你创建的值是无用的。正是这些双重描述定义了一个价值。
通常我们将构造函数视为数据,将析构函数视为控制流。变体析构函数是备用分支(许多之一),元组析构函数是并行线程(所有许多)。
并行性在诸如
之类的操作中很明显(f * g) . (h * k) = (f . h * g . k)
如果您认为控制流经函数,元组提供了一种将计算拆分为并行控制线程的方法。
这样看来,表达式是组合元组和变体以构成复杂数据结构的方法(想想 AST)。
模式匹配是组合析构函数的方法(再次想想 AST)。
【讨论】:
If-Else(或 switch)语句是关于根据手头值的属性选择不同的方式来处理值(输入)。
模式匹配是关于定义如何处理一个给定结构的值,(还要注意单例模式匹配是有意义的)。
因此,模式匹配更多的是解构值而不是做出选择,这使得它们成为在归纳结构(递归联合类型)上定义(递归)函数的一种非常方便的机制,这解释了为什么它们在 Ocaml 等语言中如此广泛地使用.
PS:您可能知道模式匹配和 If-Else “模式”从它们在数学中的特别使用中;
"如果 x 具有属性 A,则 y 否则 z" (If-Else)
“p1..pn 中的某个术语,其中 .... 是 x.. 的素数分解”((单例)模式匹配)
【讨论】: