Ok, more type hackery failure. :) :P
In my week-long pursuit of getting rid of (runtime) assert(n > 0)
and instead checking it statically, I've come up with this module:
module Nat : sig
type z
type 'n s
type ('a, 'n) nat =
Zero : ('a, z) nat
| Succ : ('a, 'n) nat -> ('a, 'n s) nat
val add : ('a, 'n) nat -> ('a, 'n s) nat
end = struct
type z
type 'n s
type ('a, 'n) nat =
Zero : ('a, z) nat
| Succ : ('a, 'n) nat -> ('a, 'n s) nat
let add n = Succ n
(*
let rec to_int n = function
| Succ a -> 1 + (to_int a)
| Zero -> 0
*)
end
This gives Peano numbers where the number is encoded in it's own type:
# Zero;;
- : ('a, Nat.z) Nat.nat = Zero
# Succ (Zero);;
- : ('a, Nat.z Nat.s) Nat.nat = Succ Zero
# add (Succ Zero);;
- : ('_a, Nat.z Nat.s Nat.s) Nat.nat = Succ (Succ Zero)
However, the last function to_int
won't compile:
Error: This pattern [Zero -> 0] matches values of type ('a, z) nat
but a pattern was expected which matches values of type
('a, ex#0 s) nat
This is, I think, because z and s is different types. Is it possible to make them the same type, and still have them as phantom types?
(Possible duplicate: type level integers in ocaml)