Advanced Type System Features
Only *syntactic values* (functions, constants, constructors) are generalized:
29.1 The value restriction & weak types
Only *syntactic values* (functions, constants, constructors) are generalized:
Relaxed value restriction: type variables that occur only in covariant positions are generalized anyway (let l = List.map Fun.id [] → 'a list).
Why: if ref [] were 'a list ref, you could store an int and read a string.
let id x = x (* 'a -> 'a — polymorphic *)
let f = id id (* '_weak1 -> '_weak1 — application, not generalized *)
let f x = id id x (* eta-expansion restores polymorphism: 'a -> 'a *)
let r = ref None (* '_weak1 option ref — prevents unsoundness *)29.2 Variance annotations
Required in signatures of abstract types for subtyping and relaxed value restriction:
! marks injectivity: type !'a t.
type +'a producer = unit -> 'a (* covariant *)
type -'a consumer = 'a -> unit (* contravariant *)
type 'a cell = { mutable v : 'a } (* invariant *)module type S = sig type +'a t val empty : 'a t end29.3 Locally abstract types
let f (type a) (x : a) = ...
let make_set (type s) (cmp : s -> s -> int) =
let module S = Set.Make (struct type t = s let compare = cmp end) in
S.of_list29.4 Explicit polymorphism & polymorphic recursion
type 'a nested = Flat of 'a | Nested of 'a list nested
let rec depth : 'a. 'a nested -> int = function (* 'a. = explicitly polymorphic *)
| Flat _ -> 0
| Nested n -> 1 + depth n (* called at 'a list *)29.5 Polymorphic record fields (higher-rank)
type mapper = { f : 'a. 'a list -> 'a list }
let apply_both { f } = (f [1;2], f ["a"])
let _ = apply_both { f = List.rev }29.6 Phantom types
Type parameters with no runtime presence, used to track states:
module File : sig
type 'mode t
type read and write
val open_read : string -> read t
val open_write : string -> write t
val read_line : read t -> string
val write_line : write t -> string -> unit
end = struct
type 'mode t = string (* just a name, for illustration *)
type read and write
let open_read p = p
let open_write p = p
let read_line _ = "data"
let write_line _ _ = ()
end
(* File.write_line (File.open_read "x") "oops" -> type error *)(* Validation states *)
type unvalidated and validated
type 'a form = { email : string }
let validate (f : unvalidated form) : validated form option = ...
let submit (f : validated form) = ...29.7 Constraints on type parameters
type 'a t = 'a constraint 'a = < name : string; .. >29.8 Nominal vs structural typing
Records & variants: nominal (type name matters).
Objects & polymorphic variants: structural (shape matters).
Module types: structural.
29.9 Type-directed disambiguation & principal types
Warnings 40–42 relate to constructor/field disambiguation. -principal flag checks principality of inferred types.
29.10 Recursive types & -rectypes
By default OCaml rejects cyclic types ('a -> 'a unified with 'a) except via objects/polymorphic variants. -rectypes relaxes this (rarely needed).
29.11 Unboxed / immediate attributes
type t = { x : float } [@@unboxed]
type small = A | B | C [@@immediate]29.12 The Type module (5.1+)
let int_id : int Type.Id.t = Type.Id.make ()
let str_id : string Type.Id.t = Type.Id.make ()
let cast_to_int (type a) (id : a Type.Id.t) (v : a) : int option =
match Type.Id.provably_equal id int_id with
| Some Type.Equal -> Some v (* here the compiler knows a = int *)
| None -> None
let _ = cast_to_int int_id 5 (* Some 5 *)
let _ = cast_to_int str_id "x" (* None *)