模式匹配,F#vs Erlang

时间:2010-08-03 19:11:38

标签: f# erlang pattern-matching ocaml

在Erlang中,我们鼓励您不要匹配您实际未处理的模式。例如:

case (anint rem 10) of
    1 -> {ok, 10}
    9 -> {ok, 25}
end;

是一种鼓励的样式,其他可能的结果会导致badmatch结果。这与Erlang中的“让它崩溃”理念是一致的。

另一方面,F#会在等效的F#代码中发出“不完整的模式匹配”,例如here

问题:F#为什么不通过扩充与等效于

的语句匹配的每个模式来有效地删除警告
|_ -> failwith "badmatch"

并使用“让它崩溃”的理念?

编辑:到目前为止有两个有趣的答案:要么避免在不处理代数数据类型的所有情况时可能发生的错误;或者因为.Net平台。找出哪个是检查OCaml的一种方法。那么,OCaml中的默认行为是什么?

编辑:消除在Erlang中没有背景的.Net人员的误解。 Erlang哲学的要点不是产生总是崩溃的坏代码。让它崩溃意味着let some other process fix the error。不是编写函数以便它可以处理所有可能的情况,而是让调用者(例如)处理自动抛出的坏情况。对于那些具有Java背景的人来说,它就像是一个带有已检查异常的语言之间的区别,它必须声明它可能返回的所有可能的异常,并且有一种语言,其中函数可能引发未明确声明的异常。

5 个答案:

答案 0 :(得分:23)

F#(以及其他具有模式匹配的语言,如Haskell和O'Caml)会隐式添加引发异常的案例。

在我看来,完成模式匹配并注意警告的最有价值的原因是它可以通过扩展您的数据类型来轻松重构,因为编译器会警告您有关尚未更新的代码新案例。

另一方面,有时确实存在应该被排除在外的情况,然后在通常是一个糟糕的错误消息的情况下放入一个包罗万象的情况是很烦人的。所以这是一个权衡。

在回答您的编辑时,默认情况下这也是O'Caml中的警告(在Haskell中使用-Wall)。

答案 1 :(得分:13)

在大多数情况下,特别是代数数据类型,忘记案例可能是一个意外,而不是有意忽略案件的决定。在强类型函数式语言中,我认为大多数函数都是完整的,因此应该处理每个案例。即使对于部分函数,​​抛出特定异常通常也是理想的,而不是使用通用模式匹配失败(例如List.head在给定空列表时抛出ArgumentException

因此,我认为编译器通常会警告开发人员。如果您不喜欢这种行为,您可以添加一个自我抛出异常的catch-all模式,或者关闭或忽略该警告。

答案 2 :(得分:11)

  

为什么F#不会删除警告

有趣的是你会问这个。静默注入运行时错误源绝对违背F#及其亲属背后的理念。它被认为是一种怪诞的憎恶。这一系列的语言都是关于静态检查的,因为类型系统的基本设计是为了促进这种静态检查。

哲学的这种明显差异恰恰是为什么F#和Python很少被比较和对比的原因。 “正如他们所说的那样,”两个人永远不会相遇“。

  

那么,OCaml中的默认行为是什么?

与F#相同:在编译时检查模式匹配的详尽性和冗余,如果发现匹配是可疑的,则发出警告。习惯风格也是一样的:您需要编写代码,以免出现这些警告。

此行为与.NET无关,事实上,此功能(来自OCaml)最近才在F#中正确实现。

例如,如果您使用let绑定中的模式来提取列表的第一个元素,因为您知道列表将始终至少包含一个元素:

let x::_ = myList

在这一系列语言中,这几乎总是表明设计缺陷。正确的解决方案是使用一种无​​法表示空列表的类型来表示非空列表。然后,静态类型检查证明您的列表不能为空,因此可以保证从代码中完全消除此运行时错误源。

例如,您可以将非空列表表示为包含头部和尾部列表的元组。然后您的模式匹配变为:

let x, _ = myList

这是详尽无遗的,因此编译器很满意并且不会发出警告。此代码在运行时不会出错

我在2004年成为这项技术的倡导者,当时我重构了大约1kLOC的商业OCaml代码,这些代码一直是应用程序中运行时错误的主要来源(尽管它们是以全部形式明确表达的)匹配引发异常的案例)。我的重构从大多数代码中删除了所有运行时错误的来源。整个应用程序的可靠性大大提高。此外,我们通过调试浪费了数周的狩猎错误,但我的重构在2天内完成。因此,这种技术确实在现实世界中带来了好处。

答案 3 :(得分:4)

Erlang因为动态类型而无法进行详尽的模式匹配,除非你在每个中都有一个全能,这很愚蠢。另一方面,Ocaml可以。 Ocaml还尝试将所有可以在编译时捕获的问题推送到编译时。

答案 4 :(得分:3)

默认情况下,OCaml会警告您不完整的匹配。您可以通过在“-w”标志中添加“p”来禁用它。这些警告的想法往往是(至少根据我的经验)它们是程序员错误的指示。特别是当你的所有模式都像Node (Node (Leaf 4) x) (Node y (Node Empty _))那样复杂时,很容易错过一个案例。当程序员确定它不会出错时,明确添加| _ -> assert false案例是一种明确的方式来表明这一点。

GHC默认关闭这些警告;但您可以使用-fwarn-incomplete-patterns

启用它