问题描述
为什么默认情况下以F#和Ocaml(以及其他语言)编写的函数不是递归的?
Why is it that functions in F# and Ocaml (and possibly other languages) are not by default recursive?
换句话说,为什么语言设计人员认为最好在如下声明中明确键入rec
是一个好主意:
In other words, why did the language designers decide it was a good idea to explicitly make you type rec
in a declaration like:
let rec foo ... = ...
,并且默认情况下不提供函数递归功能吗?为什么需要显式的rec
构造?
and not give the function recursive capability by default? Why the need for an explicit rec
construct?
推荐答案
原始ML的法国和英国后裔做出了不同的选择,并且他们的选择已沿用了数十年,一直传承至今.因此,这只是遗留问题,但确实会影响这些语言中的习惯用语.
The French and British descendants of the original ML made different choices and their choices have been inherited through the decades to the modern variants. So this is just legacy but it does affect idioms in these languages.
默认情况下,法语CAML语言家族(包括OCaml)中的函数不是递归的.通过这种选择,可以轻松地在这些语言中使用let
取代函数(和变量)定义,因为您可以在新定义的主体内引用以前的定义. F#从OCaml继承了此语法.
Functions are not recursive by default in the French CAML family of languages (including OCaml). This choice makes it easy to supercede function (and variable) definitions using let
in those languages because you can refer to the previous definition inside the body of a new definition. F# inherited this syntax from OCaml.
例如,在计算OCaml中的序列的Shannon熵时取代函数p
:
For example, superceding the function p
when computing the Shannon entropy of a sequence in OCaml:
let shannon fold p =
let p x = p x *. log(p x) /. log 2.0 in
let p t x = t +. p x in
-. fold p 0.0
请注意,高阶shannon
函数的自变量p
如何在正文的第一行中被另一个p
取代,然后在正文的第二行中被另一个p
取代.
Note how the argument p
to the higher-order shannon
function is superceded by another p
in the first line of the body and then another p
in the second line of the body.
相反,ML语言家族的英国SML分支采用了另一种选择,默认情况下,SML的fun
绑定函数是递归的.当大多数函数定义不需要访问其函数名称的先前绑定时,这将导致代码更简单.但是,被取代的函数使用了不同的名称(f1
,f2
等),这污染了范围,并有可能意外地调用错误的函数版本".现在,隐式递归fun
绑定的函数与非递归val
绑定的函数之间存在差异.
Conversely, the British SML branch of the ML family of languages took the other choice and SML's fun
-bound functions are recursive by default. When most function definitions do not need access to previous bindings of their function name, this results in simpler code. However, superceded functions are made to use different names (f1
, f2
etc.) which pollutes the scope and makes it possible to accidentally invoke the wrong "version" of a function. And there is now a discrepancy between implicitly-recursive fun
-bound functions and non-recursive val
-bound functions.
Haskell可以通过将定义限制为纯净来推断定义之间的依赖关系.这使玩具样品看起来更简单,但在其他地方却要付出沉重的代价.
Haskell makes it possible to infer the dependencies between definitions by restricting them to be pure. This makes toy samples look simpler but comes at a grave cost elsewhere.
请注意,Ganesh和Eddie给出的答案是红色鲱鱼.他们解释了为什么不能将函数组放置在巨型let rec ... and ...
中的原因,因为这会影响类型变量的泛化时间.这与rec
是SML中的默认值无关,而与OCaml无关.
Note that the answers given by Ganesh and Eddie are red herrings. They explained why groups of functions cannot be placed inside a giant let rec ... and ...
because it affects when type variables get generalized. This has nothing to do with rec
being default in SML but not OCaml.
这篇关于为什么默认情况下Ocaml/F#中的函数不递归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!