F# 中的模式匹配在幕后如何工作?
我对 F#(以及一般的函数式编程)完全陌生,但我看到示例代码中到处都使用了模式匹配。我想知道例如模式匹配实际上是如何工作的?例如,我想象它的工作方式与其他语言中的 for 循环相同,并检查集合中每个项目的匹配情况。这可能远不正确,它在幕后实际上是如何工作的?
I am completely new to F# (and functional programming in general) but I see pattern matching used everywhere in sample code. I am wondering for example how pattern matching actually works? For example, I imagine it working the same as a for loop in other languages and checking for matches on each item in a collection. This is probably far from correct, how does it actually work behind the scenes?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
它与您想象的
for
循环相差甚远:模式匹配不是循环,而是编译为高效的自动机。自动机有两种风格,我称之为“决策树”和“法国风格”。每种风格都具有不同的优点:决策树检查做出决策所需的最小值数量,但在最坏的情况下,简单的实现可能需要指数代码空间。法式风格提供了不同的时空权衡,对两者都有良好但不是最优的保证。但关于这个问题绝对权威的工作是 Luc Maranget 的优秀论文“编译2008 年 ML 研讨会上的模式匹配到良好决策树基本上展示了如何获得两全其美的效果,如果您想要一种对业余爱好者来说更容易理解的处理方法,我谦虚地说。推荐我自己的产品匹配编译启发式何时重要?< /em>
编写模式匹配编译器既简单又有趣!
It is about as far from a
for
loop as you could imagine: instead of looping, a pattern match is compiled to an efficient automaton. There are two styles of automaton, which I call the "decision tree" and the "French style." Each style offers different advantages: the decision tree inspects the minimum number of values needed to make a decision, but a naive implementation may require exponential code space in the worst case. The French style offers a different time-space tradeoff, with good but not optimal guarantees for both.But the absolutely definitive work on this problem is Luc Maranget's excellent paper "Compiling Pattern Matching to Good Decisions Trees from the 2008 ML Workshop. Luc's paper basically shows how to get the best of both worlds. If you want a treatment that may be slightly more accessible to the amateur, I humbly recommend my own offering When Do Match-Compilation Heuristics Matter?
Writing a pattern-match compiler is easy and fun!
这取决于您指的是哪种模式匹配 - 它是非常强大的构造,可以以各种方式使用。不过,我将尝试解释模式匹配如何在列表上工作。例如,您可以编写以下模式:
F# 列表实际上是一个可区分联合,包含两种情况 -
[]
表示空列表或x::xs
表示第一个列表元素x
后跟一些其他元素。在 C# 中,这可能会这样表示:上面的模式将被编译为以下内容(我使用伪代码来使其更简单):
如您所见,不涉及循环。在 F# 中处理列表时,您可以使用递归来实现循环,但模式匹配用于共同组成整个列表的单个元素 (
ConsList
)。列表上的模式匹配是可区分联合的一个具体情况,sepp2k对此进行了讨论。还有其他结构可能会出现在模式匹配中,但基本上所有这些结构都是使用某些(复杂的)
if
语句进行编译的。It depends on what kind of pattern matching do you mean - it is quite powerful construct and can be used in all sorts of ways. However, I'll try to explain how pattern matching works on lists. You can write for example these patterns:
The F# list is actually a discriminated union containing two cases -
[]
representing an empty list orx::xs
representing a list with first elementx
followed by some other elements. In C#, this might be represented like this:The patterns above would be compiled to the following (I'm using pseudo-code to make this simpler):
As you can see, there is no looping involved. When processing lists in F#, you would use recursion to implement looping, but pattern matching is used on individual elements (
ConsList
) that together compose the entire list.Pattern matching on lists is a specific case of discriminated union which is discussed by sepp2k. There are other constructs that may appear in pattern matching, but essentially all of them are compiled using some (complicated)
if
statement.不,它不循环。如果您有这样的模式匹配,
则会编译为类似以下伪代码的内容:
如果 Foo 和 Bar 是代数数据类型的构造函数(即定义为
type FooBar = Foo int int | Bar int
的类型) >) 操作x is a Foo
和x is a Bar
是简单的比较。如果它们是由活动模式定义的,则操作由那个图案。No, it doesn't loop. If you have a pattern match like this
this compiles down to something like this pseudo code:
If Foo and Bar are constructors from an algebraic data type (i.e. a type defined like
type FooBar = Foo int int | Bar int
) the operationsx is a Foo
andx is a Bar
are simple comparisons. If they are defined by an active pattern, the operations are defined by that pattern.如果您将 F# 代码编译为 .exe,请使用 Reflector 看一下可以看到 F# 代码的 C#“等效”内容。
我已经使用这种方法查看了很多 F# 示例。
If you compile your F# code to an .exe then take a look with Reflector you can see what the C# "equivalent" of the F# code.
I've used this method to look at F# examples quite a bit.