For instance, consider the following code:
type foo = Foo of int
let apply z f = f z
(* This is not allowed *)
let create_foo = Foo
(* This is allowed *)
let create_foo i = Foo i
(* This is not allowed *)
apply 1 Foo
(* This is allowed *)
apply 1 create_foo
Are data constructors special function that must be fully applied?
When used as a function, Foo
and create_foo
are identical in what they do. What's the reasoning for disallowing the usage of Foo
as a regular function that you can pass around and partially apply?
Haskell seems to allow this behaviour.
From the horse's mouth, Xavier Leroy, in this mailing list message from 2001:
The old Caml V3.1 implementation treated constructors as functions like SML. In Caml Light, I chose to drop this equivalence for several reasons:
Simplicity of the compiler. Internally, constructors are not functions, and a special case is needed to transform Succ into (fun x -> Succ x) when needed. This isn't hard, but remember that Caml Light was really a minimal, stripped-down version of Caml.
Constructors in Caml Light and OCaml really have an arity, e.g. C of int * int is really a constructor with two integer arguments, not a constructor taking one argument that is a pair. Hence, there would be two ways to map the constructor C to a function: fun (x,y) -> C(x,y) or fun x y -> C(x,y) The former is more natural if you come from an SML background (where constructors have 0 or 1 argument), but the latter fits better the Caml Light / OCaml execution model, which favors curried functions. By not treating constructors like functions, we avoid having to choose...
Code clarity. While using a constructor as a function is sometimes convenient, I would argue it is often hard to read. Writing "fun x -> Succ x" is more verbose, but easier to read, I think.
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