Just to nail this thread shut, I have been convinced of the utility of a
void type (as distinct from the unit type) in pragmatic code. Consider
the following module signature:
module type Req = sig
type a
type b
end;;
module Example(Base: Req) = struct
type a_or_b =
| A of Base.a
| B of Base.b
;;
let foo (x: a_or_b list) = ...
end;;
An important point to notice here is that the Example module signature can
not be factored into a "a part" and a "b part" without losing important
capabilities- for example, being able to pass in a list that contains both
a's and b's. Even assuming you have full control of the source code and
time and inclination (if needed) to refactor the code, a refactoring is
still not possible. So my blythe "just refactor the module" doesn't
apply.
So how do I use that module and say, in the type system, "I will never
pass in a b"? This is where the void type comes in. I can declare:
module Myreq = struct
type a = whatever;;
type b = void;;
end;;
module Myexample = Example(Myreq);;
Note that I can still call function Myexample.foo- I can call it with an
empty list, or with a list of as many A's as I want. But it's impossible
for me to create a B element.
Brian