Warning: Reason support is experimental. We are looking for beta-tester and contributors.

deriving examples

Pretty printing

The deriving preprocessor and library provide common functionality which has an obvious definition at most types. For example, it's usually easy, although tedious, to write a to_string function for a new type you've defined; deriving will save you the trouble by writing the function for you automatically. To call a deriving function at a particular type you use a special notation:

Class.method<type> argument

(Note that the terms "Class" and "method" are taken from Haskell's type classes, and has nothing to do with OCaml's object-oriented class system.)

For example, to call the show method of the Show class to convert an integer to a string you would write:

Show.show<int> 3
=>
"3"

You can also specify more complex types:

let factors = [(10,[2;5]); (11, []);  12, [2;3;4;6]]

Show.show<(int * int list) list> factors
=>
"[(10,[2; 5]); (11, []);  12, [2; 3; 4; 6]]"

To use a deriving function at a type you've defined, you need to add the phrase deriving (Class) to the end of your type definition. For example,

type 'a tree = Leaf of 'a | Branch of 'a tree * 'a * 'a tree
     deriving (Show)

 type point = { x : float; y : float }
     deriving (Show)

 let points = Branch (Leaf {x=0.0;
                            y=0.0;},
                      {x=2.0; y=2.0},
                      Branch (Leaf {x=1.0; y=1.0},
                              {x=1.0; y=0.0},
                              Leaf {x=0.0; y=1.0}))

Show.show<point tree> points
=>
"Branch
   (Leaf {x =193.11; y =132.13}, {x =211.91; y =201.11},
    Branch
      (Leaf {x =113.12; y =1.}, {x =12.7; y =44.1}, Leaf {x =0.; y
      =13.41}))"

If you want to show values of an abstract type defined in a module outside the module you should add the deriving annotation to the signature as well:

module IntStack : sig
  type t
    deriving (Show)

  val empty : t
  val push : int -> t -> t
  val top : t -> int
  val pop : t -> t
end =
struct
  type t = Stack of int list
     deriving (Show)
  let empty = Stack []
  let push item (Stack list) = Stack (item::list)
  let top (Stack (top::_)) = top
  let pop (Stack (_::rest)) = Stack rest
end

Show.show<IntStack.t>
  (IntStack.push 3 (IntStack.push 4 (IntStack.push 5 IntStack.empty)))
=>
"Stack [3; 4; 5]"

You can derive Show for most types, including recursive (and mutually recursive) types, normal and polymorphic variants, records, tuples and types containing other types for which Show has been derived. You can't derive Show for functions because there's usually no meaningful way to display them. If you have a way to display values of a type for which Show cannot be derived then you can always write your own definition and make it available to deriving; see the section "Extending definitions".

Dynamic typing

The `Typeable' class provides operations for converting between a universal type `dynamic' and any other type. Converting from dynamic to another type succeeds only if the type specified in the conversion matches the type used to create the dynamic value. The upcast operation is called mk (or make_dynamic if you prefer to be verbose). The downcasts are cast, which returns an option value, and throwing_cast, which throws an exception if the downcast fails.

type 'a tree = Leaf of 'a | Branch of 'a tree * 'a * 'a tree
  deriving (Typeable)

let items =
   [Typeable.mk<int> 3;
    Typeable.mk<float> 3.0;
    Typeable.mk<string tree> (Leaf "three")]
=>
[<abstr>; <abstr>; <abstr>]

Typeable.cast<int> (List.hd items)
=>
Some 3

Typeable.throwing_cast<int> (List.hd items)
=>
3

Typeable.cast<float> (List.hd items)
=>
None

Typeable.throwing_cast<float> (List.hd items)
=>
Exception: Typeable.CastFailure "cast failed".

Casts also work between equivalent polymorphic variant types (even if the types used for the upcast and downcast are defined differently):

type 'a seq = [`Nil | `Cons of 'a * 'a seq]
    deriving (Typeable)

let l = `Cons (3, `Cons (2, `Cons (1, `Nil)))

Typeable.cast<[`Cons of int * 'a|`Nil] as 'a>
  (Typeable.mk<int seq> l)
=>
Some (`Cons (3, `Cons (2, `Cons (1, `Nil))))

Casts don't work between record or normal variant types which are defined separately, even if the definitions are identical.

type complex = {x : float; y : float}
  deriving (Typeable)


type point = {x : float; y : float}
  deriving (Typeable)

Typeable.cast<point> (Typeable.mk<complex> {x : -1.0; y : 0.0})
=>
None

However, abstraction using module signatures does not change whether types are interconvertible, so you can use Typeable to access the representation of an abstract type if you know it.

module T :
sig
  type t
    deriving (Typeable)
  val v : t
end =
struct
  type t = int
  val v = 12
end

Typeable.cast<int> (Typeable.mk<T.t> T.v)
=>
12

Equality

There are two polymorphic equality operators in OCaml:

= tests for structural equality. == tests for physical equality. Sometimes neither of these is appropriate. Instead, we want to test for structural equality at immutable types and physical equality (identity) at mutable types (as in SML). This sort of equality tests whether two values can be used interchangeably in a program.

Eq.eq<int ref> (ref 1) (ref 1)
=>
false

let x = ref 1 in Eq.eq<int ref> x x
=>
true

Eq.eq<int list> [1;2;3] [1;2;3]
=>
true

type mpoint = { mutable x : float; mutable y : float}
    deriving (Eq)

Eq.eq<mpoint> {x = 1.0; y = 2.0} {x = 1.0; y = 2.0}
=>
false

let p = {x = 1.0; y = 2.0} in Eq.eq<mpoint> p p
=>
true

type ipoint = { x : float; y : float}
    deriving (Eq)

Eq.eq<ipoint> {x = 1.0; y = 2.0} {x = 1.0; y = 2.0}
=>
true

Serialisation

The `Pickle' class provides operations for structure-sharing serialisation (marshalling). If any value to be serialised contains two equal subvalues then only one copy of the subvalue will be serialised. Cycles that are created by mutable record fields, including references, are preserved.

All "instances" of Pickle must also be "instances" of Eq and Typeable. (As in Haskell, we use "instance" to mean a set of functions that implement the methods of a class at a particular type.)

type 'a tree = Leaf of 'a | Branch of 'a tree * 'a * 'a tree
  deriving (Eq, Typeable, Pickle)

type point = { x : float; y : float }
    deriving (Eq, Typeable, Pickle)

Pickle.to_string<point tree> points
=>
"\007\003\t\128\128\128\128\128\128\128\248?\t\128\128\128\128\128\128\128\128@\001\000\005\000\001\008\000\001\n\001\003\004\t\003\000\001\012\001\003\006\011\005\005\002\002\000\002\000\002\002\000\000\002\001\001\002\002\002"

Pickle.from_string<point tree> (Pickle.to_string<point tree> points)
=>
Branch
  (Leaf {x =193.11; y =132.13}, {x =211.91; y =201.11},
   Branch
     (Leaf {x =113.12; y =1.}, {x =12.7; y =44.1}, Leaf {x =0.; y =13.41}))

You can supply a custom definition of equality (see the section "Extending definitions") to increase sharing: see the file tests/exp.ml in the distribution for an example.

There is another class, `Dump', that provides simpler value-oriented serialisation, but doesn't deal with references or cycles.

Map

Given a type ('a1,...,'an) t, the `Functor' class will derive a map operation:

val map : ('a1->'b1) -> ... ('an->'bn} -> ('a1,...,'an) t -> ('b1,...,'bn) t

For example,

type 'a tree = Leaf of 'a | Branch of 'a tree * 'a * 'a tree
  deriving (Functor)

Functor_tree.map ((+) 1) (Branch (Leaf 3, 4, Leaf 5))
=>
(Branch (Leaf 4, 5, Leaf 6))

The <t> notation is not currently available for Functor.

Enumerations

Enumerations provide several operations for dealing with variant types where all constructors have no argument.

Enum.enum_from_to<int> 0 10
=>
[0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

type fruit = Apple | Orange | Banana | Kiwi
   deriving (Enum)

Enum.enum_from_to<fruit> Apple Kiwi
=>
[Apple; Orange; Banana; Kiwi]

Enum.succ<fruit> Orange
=>
Banana

Minimum and maximum values

Instances of bounded have maximum and minimum values:

type fruit = Apple | Orange | Banana | Kiwi
   deriving (Bounded)

(Bounded.min_bound<int * fruit>, Bounded.max_bound<int * fruit>)
=>
((-1073741824, Apple), (1073741823, Kiwi))

Extending definitions

Instead of deriving a definition automatically you can provide your own by writing a module with the same signature as the standard definitions with a name formed from the class name, an underscore, and the name of the type constructor for which you want to provide the definition.

module Eq_fruit
  : Eq.Eq with type a = fruit =
Eq.Defaults(struct
  type a = fruit
  let eq l r = match l, r with
   | Apple  , Orange
   | Orange , Apple
   | Apple  , Apple
   | Orange , Orange
   | Banana , Banana
   | Kiwi   , Kiwi   -> true
   | _               -> false
end)

Eq.eq<fruit list> [Apple; Orange; Banana] [Orange; Orange; Banana]
=>
true