解释模式匹配与切换

发布于 2024-07-06 20:14:25 字数 1719 浏览 6 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

£噩梦荏苒 2024-07-13 20:14:25

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

当我刚刚浏览了模式匹配并认为它是一个美化的 switch 语句时,我认为我没有使用代数数据类型(元组和可区分联合)进行编程的经验,并且不太明白模式匹配两者都是控制结构绑定结构。 现在我已经使用 F# 进行编程,我终于“明白了”。 模式匹配的酷炫之处在于函数式编程语言中功能的融合,因此对于外行人来说,它的欣赏并非易事。

在关于语言和 API 设计的简短两部分博客系列的第二部分中,我试图总结模式匹配为何有用的一个方面; 查看第一部分第二部分

Having formerly been one of "those people", I don't know that there's a succinct way to sum up why pattern-matching is such tasty goodness. It's experiential.

Back when I had just glanced at pattern-matching and thought it was a glorified switch statement, I think that I didn't have experience programming with algebraic data types (tuples and discriminated unions) and didn't quite see that pattern matching was both a control construct and a binding construct. Now that I've been programming with F#, I finally "get it". Pattern-matching's coolness is due to a confluence of features found in functional programming languages, and so it's non-trivial for the outsider-looking-in to appreciate.

I tried to sum up one aspect of why pattern-matching is useful in the second of a short two-part blog series on language and API design; check out part one and part two.

蓝天白云 2024-07-13 20:14:25

模式为您提供了一种小语言来描述您想要匹配的值的结构。 该结构可以是任意深度,并且您可以将变量绑定到结构化值的部分。

这使您可以非常简洁地编写内容。 您可以用一个小示例来说明这一点,例如简单类型的数学表达式的导数函数:

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) 提供非常有效的实现(带有跳转等)。

Patterns give you a small language to describe the structure of the values you want to match. The structure can be arbitrarily deep and you can bind variables to parts of the structured value.

This allows you to write things extremely succinctly. You can illustrate this with a small example, such as a derivative function for a simple type of mathematical expressions:

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)));;

Additionally, because pattern matching is a static construct for static types, the compiler can (i) verify that you covered all cases (ii) detect redundant branches that can never match any value (iii) provide a very efficient implementation (with jumps etc.).

笨死的猪 2024-07-13 20:14:25

摘自这篇博客文章

模式匹配有几个优点通过 switch 语句和方法分派:

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

Excerpt from this blog article:

Pattern matching has several advantages over switch statements and method dispatch:

  • Pattern matches can act upon ints,
    floats, strings and other types as
    well as objects.
  • Pattern matches can act upon several
    different values simultaneously:
    parallel pattern matching. Method
    dispatch and switch are limited to a single
    value, e.g. "this".
  • Patterns can be nested, allowing
    dispatch over trees of arbitrary
    depth. Method dispatch and switch are limited
    to the non-nested case.
  • Or-patterns allow subpatterns to be
    shared. Method dispatch only allows
    sharing when methods are from
    classes that happen to share a base
    class. Otherwise you must manually
    factor out the commonality into a
    separate function (giving it a
    name) and then manually insert calls
    from all appropriate places to your
    unnecessary function.
  • Pattern matching provides redundancy
    checking which catches errors.
  • Nested and/or parallel pattern
    matches are optimized for you by the
    F# compiler. The OO equivalent must
    be written by hand and constantly
    reoptimized by hand during
    development, which is prohibitively
    tedious and error prone so
    production-quality OO code tends to
    be extremely slow in comparison.
  • Active patterns allow you to inject
    custom dispatch semantics.
梦年海沫深 2024-07-13 20:14:25

我突然想到:

  1. 编译器可以判断您是否没有涵盖匹配中的所有可能性
  2. 您可以使用匹配作为分配
  3. 如果您有一个可区分的联合,则每个匹配都可以有不同的“类型”

Off the top of my head:

  1. The compiler can tell if you haven't covered all possibilities in your matches
  2. You can use a match as an assignment
  3. If you have a discriminated union, each match can have a different 'type'
來不及說愛妳 2024-07-13 20:14:25

元组有“,”,变体有 Ctor args ..这些是构造函数,它们创建东西。

模式是破坏者,它们将它们撕裂。

它们是双重概念。

更强有力地说:元组或变体的概念不能仅通过其构造函数来描述:需要析构函数,否则您创建的值是无用的。 正是这些双重描述定义了一个值。

通常我们将构造函数视为数据,将析构函数视为控制流。 变体析构函数是交替分支(众多分支之一),元组析构函数是并行线程(所有分支)。

并行性在操作中很明显,例如

(f * g) . (h * k) = (f . h * g . k) 

如果您考虑流经函数的控制,元组提供了一种将计算拆分为并行控制线程的方法。

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

模式匹配是组成析构函数的方法(再次,想想 AST)。

Tuples have "," and Variants have Ctor args .. these are constructors, they create things.

Patterns are destructors, they rip them apart.

They're dual concepts.

To put this more forcefully: the notion of a tuple or variant cannot be described merely by its constructor: the destructor is required or the value you made is useless. It is these dual descriptions which define a value.

Generally we think of constructors as data, and destructors as control flow. Variant destructors are alternate branches (one of many), tuple destructors are parallel threads (all of many).

The parallelism is evident in operations like

(f * g) . (h * k) = (f . h * g . k) 

if you think of control flowing through a function, tuples provide a way to split up a calculation into parallel threads of control.

Looked at this way, expressions are ways to compose tuples and variants to make complicated data structures (think of an AST).

And pattern matches are ways to compose the destructors (again, think of an AST).

挽容 2024-07-13 20:14:25

开关是两个前轮。

模式匹配是整个汽车。

Switch is the two front wheels.

Pattern-matching is the entire car.

兔姬 2024-07-13 20:14:25

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

  • 详尽的(没有遗漏任何案例)
  • (没有永远无法命中的案例,因为它们被先前的案例抢占了)
  • 非冗余 (考虑到所讨论的数据类型,没有不可能的模式)

这确实是一件大事。 当您第一次编写程序时,它很有帮助,当您的程序不断发展时,它也非常有用。 如果使用得当,匹配语句可以更轻松地可靠地更改代码中的类型,因为类型系统会将您指向损坏的匹配语句,这可以很好地指示您的代码的位置需要修复。

Pattern matches in OCaml, in addition to being more expressive as mentioned in several ways that have been described above, also give some very important static guarantees. The compiler will prove for you that the case-analysis embodied by your pattern-match statement is:

  • exhaustive (no cases are missed)
  • non-redundant (no cases that can never be hit because they are pre-empted by a previous case)
  • sound (no patterns that are impossible given the datatype in question)

This is a really big deal. It's helpful when you're writing the program for the first time, and enormously useful when your program is evolving. Used properly, match-statements make it easier to change the types in your code reliably, because the type system points you at the broken match statements, which are a decent indicator of where you have code that needs to be fixed.

烟雨凡馨 2024-07-13 20:14:25

If-Else(或 switch)语句是根据当前值的属性来选择不同的方式来处理值(输入)。

模式匹配是关于定义如何处理给定结构的值(另请注意,单例模式匹配是有意义的)。

因此,模式匹配更多的是解构值而不是做出选择,这使得它们成为在归纳结构(递归联合类型)上定义(递归)函数的非常方便的机制,这解释了为什么它们在 Ocaml 等语言中如此广泛地使用。

PS:您可能会从数学中的临时使用中了解模式匹配和 If-Else“模式”;

“如果 x 具有属性 A,则 y else z”(If-Else)

“p1..pn 中的某个项,其中 .... 是 x.. 的质数分解”((单例)模式匹配)

If-Else (or switch) statements are about choosing different ways to process a value (input) depending on properties of the value at hand.

Pattern matching is about defining how to process a value given its structure, (also note that single case pattern matches make sense).

Thus pattern matching is more about deconstructing values than making choices, this makes them a very convenient mechanism for defining (recursive) functions on inductive structures (recursive union types), which explains why they are so abundantly used in languages like Ocaml etc.

PS: You might know the pattern-match and If-Else "patterns" from their ad-hoc use in math;

"if x has property A then y else z" (If-Else)

"some term in p1..pn where .... is the prime decomposition of x.." ((single case) pattern match)

窗影残 2024-07-13 20:14:25

也许你可以用字符串和正则表达式来类比? 您描述您正在寻找的什么,然后让编译器自己找出如何。 它使您的代码更加简单和清晰。

顺便说一句:我发现模式匹配最有用的一点是它可以鼓励良好的习惯。 我首先处理极端情况,并且很容易检查我是否涵盖了所有情况。

Perhaps you could draw an analogy with strings and regular expressions? You describe what you are looking for, and let the compiler figure out how for itself. It makes your code much simpler and clearer.

As an aside: I find that the most useful thing about pattern matching is that it encourages good habits. I deal with the corner cases first, and it's easy to check that I've covered every case.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文