Polymorphic Variants
Thus far, whenever you've wanted to define a variant type, you have had to give
it a name, such as day
, shape
, or 'a mylist
:
type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat
type shape =
| Point of point
| Circle of point * float
| Rect of point * point
type 'a mylist = Nil | Cons of 'a * 'a mylist
Occasionally, you might need a variant type only for the return value of a single
function. For example, here's a function f
that can either return
an int
or ; you are forced to define a variant type to represent
that result:
type fin_or_inf = Finite of int | Infinity
let f = function
| 0 -> Infinity
| 1 -> Finite 1
| n -> Finite (-n)
The downside of this definition is that you were forced to defined
fin_or_inf
even though it won't be used throughout much of your program.
There's another kind of variant in OCaml that supports this kind of programming: polymorphic variants. Polymorphic variants are just like variants, except:
- You don't have declare their type or constructors before using them.
- There is no name for a polymorphic variant type. (So another name for this feature could have been "anonymous variants".)
- The constructors of a polymorphic variant
start with
`
(this the "grave accent", also called backquote, back tick, and reverse single quote; it is typically found on the same key as the~
character, near the escape key).
Using polymorphic variants, we can rewrite f
:
(* note: no type definition *)
let f = function
| 0 -> `Infinity
| 1 -> `Finite 1
| n -> `Finite (-n)
With this definition, the type of f
is
val f : int -> [> `Finite of int | `Infinity ]
This type says that f
either returns `Finite n
for some n:int
or `Infinity
. The square brackets do not denote a list, but rather
a set of possible constructors. The >
sign means that any code that
pattern matches against a value of that type must at least handle the
constructors `Finite
and `Infinity
, and possibly more. For
example, we could write:
match f 3 with
| `NegInfinity -> "negative infinity"
| `Finite n -> "finite"
| `Infinity -> "infinite"
It's perfectly fine for the pattern match to include constructors other
than `Finite
or `Infinity
, because f
is guaranteed never to
return any constructors other than those.
There are other, more compelling uses for polymorphic variants that we'll see later in the course. They are particularly useful in libraries. For now, we generally will steer you away from extensive use of polymorphic variants, because their types can become difficult to manage.