OCaml Syntaxthat i can never remember

Fan favorites

let succ ?x:(y : int = 0) () = y + 1

let foo : type a. a My_gadt.t -> unit = fun x -> ignore x

type t = { f : 'a. 'a list -> int }

Mutually recursive modules

module rec Foo : sig
  type t = Bar of Bar.t | Nil
end and Bar : sig
  type t = Foo of Foo.t | Nil
end
module rec Foo : sig
  type t = Bar of Bar.t | Nil
end = struct
  type t = Bar of Bar.t | Nil
end and Bar : sig
  type t = Foo of Foo.t | Nil
end = struct
  type t = Foo of Foo.t | Nil
end

Recursive module definitions always require explicit signatures.

For loop

let sum = ref 0 in
for i = 1 to 3 do
    sum := !sum + i
done;
assert (!sum = 6)

Note that the range is inclusive on both ends.

Universally quantified record field

type t = { f : 'a. 'a list -> int }
type t = { f : 'a. 'a list -> int }

First-Class Modules

First-class module parameter (module-style)

val min : (module Comparable.S with type t = 'a) -> 'a -> 'a -> 'a
let min (type a)
  (module Compare : Comparable.S with type t = a)
  (x : a) (y : a) =
  if Compare.( < ) x y then x else y

Named first-class module parameter (module-style)

val min : compare:(module Comparable.S with type t = 'a) -> 'a -> 'a -> 'a
let min (type a)
  ~compare:(module Compare : Comparable.S with type t = a)
  (x : a) (y : a) =
  if Compare.( < ) x y then x else y

As far as I can tell there is no way to express an optional parameter in this way, even if you provide a default.

First-class module parameter (value-style)

val min : (module Comparable.S with type t = 'a) -> 'a -> 'a -> 'a
let min (type a)
  (compare : (module Comparable.S with type t = a))
  (x : a) (y : a) =
  let module Compare = (val compare) in
  if Compare.( < ) x y then x else y

Named first-class module parameter (value-style)

val min : compare:(module Comparable.S with type t = 'a) -> 'a -> 'a -> 'a
let min (type a)
  ~(compare : (module Comparable.S with type t = a))
  (x : a) (y : a) =
  let module Compare = (val compare) in
  if Compare.( < ) x y then x else y

Named optional first-class module parameter with default (value-style)

val min : ?compare:(module Comparable.S with type t = 'a) -> 'a -> 'a -> 'a
let min (type a)
  ?(compare : (module Comparable.S with type t = a) = (module struct
    type t = a
    let (<) _ _ = false
    (* etc *)
  end))
  (x : a) (y : a) =
  let module Compare = (val compare) in
  if Compare.( < ) x y then x else y

The inline module is only necessary if you need to refer to type variables from the signature. For simpler module types, you can provide a named module as the default with ?(m : S = (module M)).

First-class module argument

min (module Int) 1 2

Function Signatures

Annotated return type

val succ : int -> int
let succ x : int = x + 1

Annotated positional argument

val succ : int -> int
let succ (x : int) = x + 1

Annotated return type and positional argument

val succ : int -> int
let succ (x : int) : int = x + 1

Named argument

val succ : x:int -> int
let succ ~x = x + 1

Renamed argument

val succ : x:int -> int
let succ ~x:y = y + 1

Named argument with annotated return type

val succ : x:int -> int
let succ ~x : int = x + 1

Note that the space between the identifier and the colon is significant to disambiguate this from a renamed argument.

Renamed argument with annotated return type

val succ : x:int -> int
let succ ~x:y : int = y + 1

The space between the identifier and the second colon is no longer required, as there is no more ambiguity.

Annotated named argument

val succ : x:int -> int
let succ ~(x : int) = x + 1

Annotated renamed argument

val succ : x:int -> int
let succ ~x:(y : int) = y + 1

Optional argument

val succ : ?x:int -> unit -> int option
let succ ?x () = Option.map ~f:(fun n -> n + 1) x

Note that optional arguments without subsequent positional arguments will generate a compiler warning, so we add a final unit argument to get around that. See here for more information.

Optional argument with a default value

val succ : ?x:int -> unit -> int
let succ ?(x = 0) () = x + 1

Annotated optional argument

val succ : ?x:int -> unit -> int option
let succ ?(x : int option) () = Option.map ~f:(fun n -> n + 1) x

Annotated optional argument with a default value

val succ : ?x:int -> unit -> int
let succ ?(x : int = 0) () = x + 1

Renamed annotated optional argument with a default value

val succ : ?x:int -> unit -> int
let succ ?x:(y : int = 0) () = y + 1

Explicit passing of an optional argument

let succ ?(x : int = 0) () = x + 1
let one = succ ?x:None ()
let two = succ ?x:(Some one) ()
let negative_succ ?(x : int option) () = -(succ ?x ())

Locally abstract type (monomorphic)

val foo : 'a My_gadt.t -> unit
let foo (type a) (x : a My_gadt.t) = ignore x

You will often see type variables introduced like this so that a GADT’s phantom can vary over different branches of a match statement. See here for more information.

Locally abstract type (polymorphic)

val foo : 'a My_gadt.t -> unit
let foo : type a. a My_gadt.t -> unit =
  fun x -> ignore x

This is useful when you have a recursive GADT where the components of a value have a different phantom type than the value itself. See here for more information.