Constructors with several arguments

Consider this interactive session:

utop # type a = A of int * int;;
type a = A of int * int
utop # type b = B of (int * int);;
type b = B of (int * int)
utop # A (3,4);;
a = A (3, 4)
utop # A ((3,4));;
a = A (3, 4)
utop # let t = (3,4);;
val t : int * int = (3, 4)
utop # A t;;
Error: The constructor A expects 2 argument(s),
but is applied here to 1 argument(s)
utop # B (3,4);;
b = B (3, 4)
utop # B t;;
b = B (3, 4)

There is nothing wrong here: A has two arguments, B one. Still I find it ugly that values of type a are printed in exactly the same way as values of type b. (The types themselves are distinguishable when printed).
Would it make sense to print variants whose only argument is a literal tuple like this: B ((3,4)) ?
Also, A ((3,4)) is parsed as A (3,4) and is accepted, although the first form to me intuitively looks like a single argument to the constructor. Would it be cleaner to reject A ((3,4))?
Finally, if backwards compatibility were not an issue, would the language not work just as well if only constructors with one (possibly tuple) argument were allowed at all?


I believe it would, as you’ve shown you can always encode an n-ary constructor into an unary constructor with tuple of arguments. Since the language does not treat constructors as functions (unlike SML, which from what my casual testing does not have n-ary constructors to begin with), there are no concerns about partially applied constructors.

OCaml’s revised syntax addressed this point. In the revised syntax, the two declarations are:

type a = [ A of int and int ]
type b = [ B of (int * int) ]

and values have to be constructed differently:

value a = A 3 4
value b = B (3, 4)

Polymorphic variants, incidentally, are implemented as you say - they are always a tuple. There is a performance benefit to the flat representation.

1 Like

Will this allow for partial construction? Looking at the and there, I guess no?

No - it was just a revised syntax. It’s also really just a piece of OCaml history now!