Module Base__Type_equal
The purpose of Type_equal is to represent type equalities that the type checker otherwise would not know, perhaps because the type equality depends on dynamic data, or perhaps because the type system isn't powerful enough.
A value of type (a, b) Type_equal.t represents that types a and b are equal. One can think of such a value as a proof of type equality. The Type_equal module has operations for constructing and manipulating such proofs. For example, the functions refl, sym, and trans express the usual properties of reflexivity, symmetry, and transitivity of equality.
If one has a value t : (a, b) Type_equal.t that proves types a and b are equal, there are two ways to use t to safely convert a value of type a to a value of type b: Type_equal.conv or pattern matching on Type_equal.T:
let f (type a) (type b) (t : (a, b) Type_equal.t) (a : a) : b =
  Type_equal.conv t a
let f (type a) (type b) (t : (a, b) Type_equal.t) (a : a) : b =
  let Type_equal.T = t in aAt runtime, conversion by either means is just the identity -- nothing is changing about the value. Consistent with this, a value of type Type_equal.t is always just a constructor Type_equal.T; the value has no interesting semantic content. Type_equal gets its power from the ability to, in a type-safe way, prove to the type checker that two types are equal. The Type_equal.t value that is passed is necessary for the type-checker's rules to be correct, but the compiler could, in principle, not pass around values of type Type_equal.t at runtime.
type ('a, 'b) t=|T : ('a, 'a) t
val sexp_of_t : ('a -> Base.Sexp.t) -> ('b -> Base.Sexp.t) -> ('a, 'b) t -> Base.Sexp.t
type ('a, 'b) equal= ('a, 'b) tjust an alias, needed when
tgets shadowed below
val refl : ('a, 'a) tval sym : ('a, 'b) t -> ('b, 'a) tval trans : ('a, 'b) t -> ('b, 'c) t -> ('a, 'c) tval conv : ('a, 'b) t -> 'a -> 'bconv t xuses the type equalityt : (a, b) tas evidence to safely castxfrom typeato typeb.convis semantically just the identity function.In a program that has
t : (a, b) twhere one has a value of typeathat one wants to treat as a value of typeb, it is often sufficient to pattern match onType_equal.Trather than useconv. However, there are situations where OCaml's type checker will not use the type equalitya = b, and one must useconv. For example:module F (M1 : sig type t end) (M2 : sig type t end) : sig val f : (M1.t, M2.t) equal -> M1.t -> M2.t end = struct let f equal (m1 : M1.t) = conv equal m1 endIf one wrote the body of
Fusing pattern matching onT:let f (T : (M1.t, M2.t) equal) (m1 : M1.t) = (m1 : M2.t)this would give a type error.
val detuple2 : ('a1 * 'a2, 'b1 * 'b2) t -> ('a1, 'b1) t * ('a2, 'b2) tval tuple2 : ('a1, 'b1) t -> ('a2, 'b2) t -> ('a1 * 'a2, 'b1 * 'b2) t
module type Injective = sig ... endInjectiveis an interface that states that a type is injective, where the type is viewed as a function from types to other types. The typical usage is:
module type Injective2 = sig ... endInjective2is for a binary type that is injective in both type arguments.
module Composition_preserves_injectivity : functor (M1 : Injective) -> functor (M2 : Injective) -> Injective with type 'a t = 'a M1.t M2.tComposition_preserves_injectivityis a functor that proves that composition of injective types is injective.
module Id : sig ... endIdprovides identifiers for types, and the ability to test (viaId.same) at runtime if two identifiers are equal, and if so to get a proof of equality of their types. Unlike values of typeType_equal.t, values of typeId.tdo have semantic content and must have a nontrivial runtime representation.