我一直在尝试向几个人解释switch语句和模式匹配(F#)之间的区别,但我还没有真正解释它.大多数时候他们只是看着我说"为什么你不只是使用if..then..else".
你会如何向他们解释?
编辑!感谢大家的精彩答案,我真的希望能够标出多个正确的答案.
以前曾经是"那些人"之一,我不知道有一种简洁的方法可以总结出为什么模式匹配是如此美味的好.这是经验.
回到我刚看了一下模式匹配并认为它是一个美化的开关语句时,我认为我没有使用代数数据类型(元组和有区别的联合)进行编程的经验,并且没有看到模式匹配是两者兼而有之对照构建体和结合构建体.既然我已经用F#编程了,我终于"明白了".模式匹配的酷感是由功能编程语言中的功能集合而来的,因此对外人来说欣赏是非常重要的.
我试图总结一个方面,为什么模式匹配在关于语言和API设计的简短的两部分博客系列的第二部分中是有用的; 查看第一部分和第二部分.
模式为您提供了一种小语言来描述您想要匹配的值的结构.结构可以任意深度,您可以将变量绑定到结构化值的某些部分.
这使您可以非常简洁地编写内容.您可以通过一个小例子来说明这一点,例如简单类型的数学表达式的派生函数:
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)提供非常有效的实现(具有跳转等). ).
摘自此博客文章:
与switch语句和方法分派相比,模式匹配有几个优点:
模式匹配可以对int,浮点数,字符串和其他类型以及对象起作用.
模式匹配可以同时作用于几个不同的值:并行模式匹配.方法调度和切换限于单个值,例如"this".
模式可以嵌套,允许在任意深度的树上进行调度.方法调度和切换仅限于非嵌套情况.
Or模式允许共享子模式.方法分派仅允许在方法来自碰巧共享基类的类时进行共享.否则,您必须手动将共性分解为单独的函数(为其命名),然后手动将来自所有适当位置的调用插入到不必要的函数中.
模式匹配提供冗余检查,捕获错误.
嵌套和/或并行模式匹配由F#编译器为您优化.OO等价物必须手工编写并在开发过程中不断手动重新优化,这非常繁琐且容易出错,因此生产质量的OO代码相比之下往往非常慢.
活动模式允许您注入自定义调度语义.
脱离我的头顶:
编译器可以判断您是否未涵盖匹配中的所有可能性
您可以将匹配用作作业
如果你有一个有区别的联盟,每个比赛可以有不同的'类型'
开关是两个前轮。
模式匹配是整个汽车。
元组有","和Variants有Ctor args ..这些是构造函数,它们创造了东西.
模式是析构函数,它们将它们分开.
他们是双重概念.
更强有力地说:元组或变体的概念不能仅仅通过它的构造函数来描述:析构函数是必需的,或者你创造的值是无用的.正是这些双重描述定义了一个价值.
通常我们将构造函数视为数据,将析构函数视为控制流.变体析构函数是备用分支(许多中的一个),元组析构函数是并行线程(所有这些都是).
并行性在诸如此类的操作中很明显
(f * g) . (h * k) = (f . h * g . k)
如果你想到控制流经一个函数,元组提供了一种将计算分解为并行控制线程的方法.
以这种方式看,表达式是组合元组和变体以制作复杂数据结构的方法(想想AST).
模式匹配是构成析构函数的方法(再次考虑AST).