Created
January 14, 2019 13:24
-
-
Save jtpaasch/ca52e9ad795e763aaa4958247e195543 to your computer and use it in GitHub Desktop.
Functors in OCaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (*********************************************************) | |
| (** Simple functor example. *) | |
| (** A simple signature. *) | |
| module type X = sig | |
| val x : int | |
| end | |
| (** Here's a fuctor. | |
| * It takes an input: [M], which is an implementation | |
| * of type [X]. | |
| * It produces an output, namely the structure defined | |
| * in the body of the [struct]. *) | |
| module IncX (M : X) = struct | |
| let x = M.x + 1 | |
| end | |
| (* A functor is a parameterized structure. Here, [M] is the param. | |
| * The structure it produces depends on the parameter, [M]. *) | |
| (** Here's a simple module that matches the type [X]. *) | |
| module A = struct | |
| let x = 0 | |
| end | |
| (* [A.x] is [0:int]. *) | |
| (** Let's build an [IncX] module, using [A] as input. *) | |
| module B = IncX(A) | |
| (* What's the value of [B.x]? It's [1:int]. Why? | |
| * Because [IncX.x] is [M.x + 1], and in this case, | |
| * [M] is [A], so it's [A.x + 1] => [0 + 1] => [1]. *) | |
| (** We can build another one on top of that. *) | |
| module C = IncX(B) | |
| (** What's the value of [C.x]? It's [2:int], because | |
| * [C.x] is [M.x + 1] and [M] is [B]. So that's | |
| * [B.x + 1], which is [1 + 1] => [2]. *) | |
| (** A functor needn't care about its input. | |
| * Here's one that ignores the input altogether. *) | |
| module MakeY (M : X) = struct | |
| let y = 42 | |
| end | |
| (*********************************************************) | |
| (** Alternative syntax. *) | |
| (** The following two syntaxes are equivalent. *) | |
| module F (M : X) = struct end | |
| module F = functor (M : X) -> struct end | |
| (* The second one uses the [functor] keyword, so it's like | |
| * an anonymous function built with the [fun] keyword. *) | |
| (*********************************************************) | |
| (** Multiple parameters. *) | |
| (** Here's another simple module signature. *) | |
| module type Y = sig | |
| val y : int | |
| end | |
| (** Functors can have multiple parameters. *) | |
| module IncXY (M : X) (N : Y) = struct | |
| let x = M.x + 1 | |
| let y = N.y + 2 | |
| end | |
| (** Here's an implementation of [Y]. *) | |
| module D = struct | |
| let y = 100 | |
| end | |
| (** Let's create a structure using [IncXY]. *) | |
| module E = IncXY(A)(D) | |
| (** What's the value of [E.x]? It's [1:int], because [A.x] is [0], | |
| * plus [1], makes [1]. | |
| * What's the value of [E.y]? it's [102:int], because [D.y] is [100], | |
| * plus [2], makes [102]. *) | |
| (*********************************************************) | |
| (** Using standard library functors. *) | |
| (** [Map]s can have any kind of key. You need to tell it | |
| * what kind of key you want, and you need to tell it | |
| * how to determine if one is prior to another in order. *) | |
| (** The [Map.Make] functor requires that you give it an [OrderedType] | |
| * module as a parameter. That requires that you specify a type [t] | |
| * and a [compare] function. We can make one easy: *) | |
| module IntOrderedType = struct | |
| type t = int | |
| let compare = Pervasives.compare | |
| end | |
| (** Now we can instantiate a [Map], with [Int]s for keys. *) | |
| module IntMap = Map.Make(IntOrderedType) | |
| (** An empty [IntMap]. *) | |
| let m0 = IntMap.empty;; | |
| (** Add the value ["one"] with key [1]. *) | |
| let m1 = IntMap.add 1 "one" m0;; | |
| (** Find the value for key [1]. *) | |
| IntMap.find 1 m1;; | |
| (** Check if a key is in a map. *) | |
| IntMap.mem 1 m1;; | |
| IntMap.mem 42 m1;; | |
| (** See all mapped items. *) | |
| IntMap.bindings m1;; | |
| (** The [String] module already has a type [t] = [string] | |
| * and a [compare] function. So we can make a map with | |
| * [String] keys too. *) | |
| module StringMap = Map.Make(String) | |
| let s0 = StringMap.empty;; | |
| let s1 = StringMap.add "one" 1 s0;; | |
| StringMap.find "one" s1;; | |
| StringMap.mem "one" s1;; | |
| StringMap.mem "two" s1;; | |
| let s2 = StringMap.add "three" 3 s1;; | |
| StringMap.bindings s2;; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment