I noticed a style of defining top functions without its arguments, as in:
let f =
let aux1 = ... in
let aux2 ... = ... in
(* now really define the function *)
let f x y z = ... in
f
This way aux values are defined within the local scope but evaluated once. I wonder if there is any performance advantage writing in this style when compared to the more “conventional”(?) style:
let f x y z =
let aux1 = ... in
let aux2 ... = ... in
...
2 Likes
There could be, depends on if aux1
/aux2
are expensive to calculate. Some people just don’t like doing extra work in functions if it can be avoided especially if the function is in a hot path. Some functions are called only once so it doesn’t really matter.
It can also be useful for controlling and scoping side-effects. Consider this id generation function, for example:
let generate_id =
let last_id = ref 0 in
fun () ->
incr last_id;
!last_id
4 Likes
As an example, this style is often used with the re
library. There’s a Re.t
type which describes regexps (a sort of AST I suppose) and a Re.re
type which is for compiled regexps (a sort of DFA maybe). There’s a function Re.compile
to turn Re.t
into Re.re
, and the rest of the library expects Re.re
values. Since Re.compile
can be expensive, this patterns allows the compiled regexp to have local scope but a global lifetime:
let parse_line =
let re = Re.compile (Re.seq [Re.alt [...]]) in
fun line ->
match Re.exec re line with
...
4 Likes