F# 解释模式匹配与切换

F# 解释模式匹配与切换,f#,pattern-matching,ocaml,sml,F#,Pattern Matching,Ocaml,Sml,我一直在试图向一些人解释switch语句和模式匹配(F#)之间的区别,但我并不能很好地解释清楚。大多数时候,他们只是看着我说:“那么为什么不使用if..then..else呢?” 你会如何向他们解释 编辑!谢谢大家的好答案,我真的希望我能标记多个正确答案 也许你可以用字符串和正则表达式做个类比?您可以描述您正在寻找的内容,并让编译器自行决定如何查找。它使您的代码更加简单和清晰 顺便说一句:我发现模式匹配最有用的地方是它鼓励良好的习惯。我先处理角落案例,很容易检查我是否涵盖了每一个案例。我以前是“

我一直在试图向一些人解释switch语句和模式匹配(F#)之间的区别,但我并不能很好地解释清楚。大多数时候,他们只是看着我说:“那么为什么不使用if..then..else呢?”

你会如何向他们解释


编辑!谢谢大家的好答案,我真的希望我能标记多个正确答案

也许你可以用字符串和正则表达式做个类比?您可以描述您正在寻找的内容,并让编译器自行决定如何查找。它使您的代码更加简单和清晰


顺便说一句:我发现模式匹配最有用的地方是它鼓励良好的习惯。我先处理角落案例,很容易检查我是否涵盖了每一个案例。

我以前是“那些人”中的一员,我不知道有什么简洁的方法来总结为什么模式匹配如此美味。这是经验性的

当我刚刚浏览了模式匹配并认为它是一个美化的switch语句时,我认为我没有使用代数数据类型(元组和有区别的并集)编程的经验,也不太明白模式匹配既是一个控制构造又是一个绑定构造。现在我已经用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)提供非常有效的实现(使用跳转等)。

    开关是两个前轮

    模式匹配是指整个汽车。

    摘自:

    与开关语句和方法调度相比,模式匹配有几个优点:

    • 模式匹配可以作用于int, 浮点数、字符串和其他类型 以及对象
    • 模式匹配可以作用于多个 同时使用不同的值: 并行模式匹配。方法 调度和切换仅限于单个 值,例如“this”
    • 模式可以嵌套,允许 任意树上的调度 深度方法调度和切换受到限制 对于非嵌套的情况
    • 或模式允许创建子模式 共享。方法分派只允许 当方法来自时共享 碰巧共享一个基的类 班级。否则必须手动执行 将共性因素分解成一个整体 单独的功能(给它一个 然后手动插入呼叫 从所有合适的地方到你的 不必要的功能
    • 模式匹配提供冗余 检查哪些捕获错误
    • 嵌套和/或并行模式 匹配项由 F#编译器。OO等价物必须 经常手写 在运行期间手动重新优化 发展,这是令人望而却步的 这样做既乏味又容易出错 产品质量OO代码倾向于 相比之下,速度要慢得多
    • 活动模式允许您注入 自定义分派语义

    OCaml中的模式匹配除了在上面描述的几种方式中更具表现力之外,还提供了一些非常重要的静态保证。编译器将为您证明模式匹配语句包含的案例分析是:

    • 详尽无遗(无遗漏案例)
    • 非冗余(没有因为被前一个案例抢先而无法命中的案例)
    • 声音(考虑到所讨论的数据类型,没有不可能的模式)
    这真是一件大事。它在您第一次编写程序时非常有用,在您的程序不断发展时也非常有用。如果使用得当,match语句可以更容易地可靠地更改代码中的类型,因为类型系统会将您指向断开的match语句,这是需要修复的代码所在位置的良好指示器。

    元组有“,”而变体有Ctor参数。。这些是构造器,他们创造东西

    模式是析构函数,它们将它们撕开

    它们是双重概念

    更有力地说:元组或变量的概念不能仅由其构造函数来描述:析构函数是必需的,或者所生成的值是无用的。正是这些双重描述定义了一个值

    通常我们认为构造函数是数据,析构函数是控制流。变量析构函数是备用分支(许多分支之一),元组析构函数是并行线程(所有分支)

    这种并行性在诸如

    (f * g) . (h * k) = (f . h * g . k) 
    
    如果您认为控件流经一个函数,元组提供了一种将计算拆分为控件的并行线程的方法

    从这个角度看,表达式是组成元组和变体的方法,以形成复杂的数据结构(比如AST)

    模式匹配是组成析构函数的方法(同样,考虑AST)。