我一直试图向几个人解释switch语句和模式匹配(F#)之间的区别,但我还没有真正能够解释它。大多数时候他们只是看着我说“那你为什么不用if..then..else”。
你会如何向他们解释?
EDIT!感谢大家的精彩答案,我真的希望能够标出多个正确的答案。
答案 0 :(得分:37)
以前曾是“那些人”之一,我不知道有一种简洁的方法可以总结出为什么模式匹配是如此美味的好。这是经验。
当我刚看了一下模式匹配并认为它是一个美化的开关语句时,我认为我没有使用代数数据类型(元组和有区别的联合)进行编程的经验,并且没有看到那种模式匹配既是控制构造又是一个绑定构造。既然我已经用F#编程了,我终于“明白了”。模式匹配的酷感是由功能编程语言中的功能集合而来的,所以对外人来说欣赏是非常重要的。
我试图总结一个方面,为什么模式匹配在关于语言和API设计的简短的两部分博客系列的第二部分中是有用的;查看part one和part two。
答案 1 :(得分:30)
模式为您提供了一种小语言来描述您想要匹配的值的结构。结构可以任意深度,您可以将变量绑定到结构化值的部分。
这可以让你非常简洁地写出来。您可以通过一个小例子来说明这一点,例如简单类型的数学表达式的派生函数:
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)提供非常有效的实现(使用跳等等。)。
答案 2 :(得分:15)
模式匹配与switch语句和方法分派相比有几个优点:
答案 3 :(得分:8)
脱离我的头顶:
答案 4 :(得分:5)
开关是两个前轮。
模式匹配就是整车。
答案 5 :(得分:5)
元组有“,”和Variants有Ctor args ..这些是构造函数,它们创造了东西。
模式是析构函数,它们将它们分开。
他们是双重概念。
更强有力地说:元组或变体的概念不能仅仅通过它的构造函数来描述:析构函数是必需的,或者你创造的值是无用的。正是这些双重描述定义了一个值。
通常我们将构造函数视为数据,将析构函数视为控制流。变体析构函数是备用分支(许多中的一个),元组析构函数是并行线程(所有这些都是)。
并行性在
等操作中很明显(f * g) . (h * k) = (f . h * g . k)
如果你想到控制流经一个函数,元组提供了一种将计算分解为并行控制线程的方法。
以这种方式看,表达式是组合元组和变体以构建复杂数据结构的方法(想想AST)。
模式匹配是组成析构函数的方法(再次考虑AST)。
答案 6 :(得分:3)
OCaml中的模式匹配,除了如上所述的几种方式中更具表现力之外,还提供了一些非常重要的静态保证。编译器将为您证明您的模式匹配语句所包含的案例分析是:
这是一个非常重要的事情。当你第一次编写程序时它很有用,并且在你的程序不断发展时非常有用。如果使用得当,匹配语句可以更容易地可靠地更改代码中的类型,因为类型系统将您指向损坏的匹配语句,这是您需要修复代码的适当指标。
答案 7 :(得分:0)
If-Else(或switch)语句是关于根据当前值的属性选择处理值(输入)的不同方法。
模式匹配是关于定义如何处理给定结构的值,(还要注意单个案例模式匹配是有意义的)。
因此,模式匹配更多的是解构值而不是选择,这使得它们成为在归纳结构(递归联合类型)上定义(递归)函数的一种非常方便的机制,这解释了为什么它们如Ocaml等语言如此丰富地使用。
PS:您可能知道模式匹配和If-Else“模式”来自他们在数学中的临时使用;
“如果x具有属性A,则y其他z”(If-Else)
“p1..pn中的某个术语,其中....是x的主要分解..”((单例)模式匹配)
答案 8 :(得分:-1)
也许你可以用字符串和正则表达式进行类比?您描述了您正在寻找的,让编译器为自己找出 的方式。它使您的代码更简单,更清晰。
顺便说一句:我发现关于模式匹配最有用的是它鼓励良好的习惯。我处理了第一个的角落案例,并且很容易检查我是否涵盖了所有案例。