Why is it that functions in F# and OCaml (and possibly other languages) are not by default recursive?
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 ... = ...
and not give the function recursive capability by default? Why the need for an explicit rec
construct?
Function ExpressionFunction in ocaml is a expression. That means, a function is a value that represents the function. This is also called anonymous function, lambda. Parenthesis is used for grouping, not function call.
We've seen how to assign functions to variables. Now let's take a look at how we might utilize the fact that functions are first class functions in OCaml. The kind community at Stack Overflow has generated a list of examples in other languages.
In OCaml, like in any functional language, functions themselves are values. If functions are values, they must also have types. By typing print_endline;; in the REPL you can see that its type is string -> unit . The arrow type string -> unit means that it's a function from type string to another type named unit .
OCaml is a functional (applicative) programming language, but also an imperative language, and also an object-oriented language.
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.
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.
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
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.
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 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With