Muh*_*uri 14 erlang f# ocaml pattern-matching
在Erlang中,我们鼓励您不要匹配您实际未处理的模式.例如:
case (anint rem 10) of
1 -> {ok, 10}
9 -> {ok, 25}
end;
Run Code Online (Sandbox Code Playgroud)
是一种鼓励的风格,其他可能的结果导致badmatch结果.这与Erlang中的"让它崩溃"理念是一致的.
另一方面,F#会在等效的F#代码中发出"不完整的模式匹配",就像这里一样.
问题是:为什么F#不会通过增加与等效语句匹配的每个模式来有效地删除警告
|_ -> failwith "badmatch"
Run Code Online (Sandbox Code Playgroud)
并使用"让它崩溃"的理念?
编辑:到目前为止有两个有趣的答案:要么避免在不处理代数数据类型的所有情况时可能出现的错误; 或者因为.Net平台.找出哪个是检查OCaml的一种方法.那么,OCaml的默认行为是什么?
编辑:消除在Erlang没有背景的.Net人员的误解.Erlang哲学的要点不是产生总是崩溃的坏代码.让它崩溃意味着让其他进程修复错误.不是编写函数以便它可以处理所有可能的情况,而是让调用者(例如)处理自动抛出的坏情况.对于那些具有Java背景的人来说,它就像是一个带有已检查异常的语言之间的区别,它必须声明它可能会返回的每个可能的异常,以及一个语言,其中函数可能引发未明确声明的异常.
GS *_*ica 23
F#(以及其他具有模式匹配的语言,如Haskell和O'Caml)会隐式添加引发异常的案例.
在我看来,完成模式匹配和关注警告的最有价值的原因是它通过扩展您的数据类型使得重构变得容易,因为编译器将警告您有关尚未使用新数据更新的代码案件.
另一方面,有时确实存在应该被排除在外的情况,然后必须通过一个通常是错误的错误消息的所有情况进行处理是令人讨厌的.所以这是一个权衡.
在回答您的编辑时,默认情况下这也是O'Caml中的警告(在Haskell中使用-Wall).
kvb*_*kvb 13
在大多数情况下,尤其是代数数据类型,忘记案例可能是一个意外,而不是有意忽略案件的决定.在强类型函数式语言中,我认为大多数函数都是完整的,因此应该处理每个案例.即使对于部分函数,抛出特定异常通常也是理想的,而不是使用通用模式匹配失败(例如List.head,ArgumentException当给出空列表时抛出一个).
因此,我认为编译器通常会警告开发人员.如果您不喜欢此行为,则可以添加自身引发异常的catch-all模式,也可以关闭或忽略该警告.
Jon*_*rop 11
为什么F#不会删除警告
有趣的是你会问这个.静默注入运行时错误源绝对违背F#及其亲属背后的理念.它被认为是一种怪诞的憎恶.这个语言系列都是关于静态检查的,在某种程度上,类型系统的基本设计是为了促进这些类型的静态检查.
这种哲学上的明显差异恰恰是为什么F#和Python很少被比较和对比的原因.正如他们所说的那样,"两个人永远不会相遇".
那么,OCaml的默认行为是什么?
与F#相同:在编译时检查模式匹配的详尽性和冗余,如果发现匹配是可疑的,则发出警告.惯用风格也是相同的:您需要编写代码,以便不显示这些警告.
这种行为与.NET无关,事实上,这个功能(来自OCaml)最近才在F#中正确实现.
例如,如果您使用let绑定中的模式来提取列表的第一个元素,因为您知道列表将始终至少包含一个元素:
let x::_ = myList
Run Code Online (Sandbox Code Playgroud)
在这一系列语言中,这几乎总是表明设计缺陷.正确的解决方案是使用一种无法表示空列表的类型来表示非空列表.然后,静态类型检查证明您的列表不能为空,因此可以保证从代码中完全消除此运行时错误源.
例如,您可以将非空列表表示为包含头部和尾部列表的元组.然后您的模式匹配变为:
let x, _ = myList
Run Code Online (Sandbox Code Playgroud)
这是详尽无遗的,因此编译器很高兴并且不会发出警告.此代码在运行时不会出错.
我在2004年成为这项技术的倡导者,当时我重构了大约1kLOC的商业OCaml代码,这些代码一直是应用程序中运行时错误的主要来源(尽管它们是以全部匹配案例的形式明确表示的提出例外).我的重构从大多数代码中删除了所有运行时错误的来源.整个应用程序的可靠性大大提高.此外,我们通过调试浪费了数周的狩猎错误,但我的重构在2天内完成.所以这种技术确实在现实世界中带来了好处.
由于动态类型,Erlang 不能有详尽的模式匹配,除非你在每个中都有一个包罗万象的东西,这很愚蠢。另一方面,Ocaml 可以。Ocaml 还尝试将所有可以在编译时捕获的问题推送到编译时。