Skip to content

Instantly share code, notes, and snippets.

@dbramucci
Created October 21, 2020 01:44
Show Gist options
  • Save dbramucci/d3f573bd0f489fb06e32d489d5542830 to your computer and use it in GitHub Desktop.
Save dbramucci/d3f573bd0f489fb06e32d489d5542830 to your computer and use it in GitHub Desktop.
Example of using OCaml's module system for adhoc polymorphic infix operators.
(*
If you want, you can replace all
+?
with
+
and this will still work.
It's just that the default (+) for `int` will be shadowed after the
let Open Num in
line
*)
(* Resources used during writing:
* https://ocaml.org/learn/tutorials/modules.html
Used for basic module syntax/intro
* https://medium.com/@huund/do-not-open-6e5d3070c118
Used to discover syntax for local module imports
* https://caml.inria.fr/pub/docs/manual-ocaml/moduleexamples.html
Contained the example of with type element = Elt.t for unabstracting types
* https://try.ocamlpro.com/
Used to interactively develop and run this sample.
*)
(* analogous to typeclass Numbertype Num where *)
module type Number_type =
sig
type num
val (+?) : num -> num -> num
val one : num
end
(* Analogous to instance (Number_type Int) *)
module Integer : (Number_type with type num = int) =
struct
type num = int
let (+?) = (+)
let one = 1
end
(*
The
with type num = float
is there to allow the caller to use the result of (+?) as an int
Otherwise, it would be an abstract type
(like a Haskell module that doesn't export the constructors for a Number newtype)
And you couldn't do anything other than addition with the result.
Nor could you plug in ints constructed outside of the module
*)
module Float : (Number_type with type num = float) =
struct
type num = float
let (+?) = (+.)
let one = 1.0
end
(* Here is how we can use the module to write monomorphic code *)
let rec fib_int n =
(*
The let open brings all functions in the Integer module into the local scope
*)
let open Integer in
match n with
| 0 -> one
| 1 -> one
| n -> fib_int (n - 1) +? fib_int (n - 2)
(*
Same as fib_int except we open Float to indicate we want float's
instance of (+?)
very roughly analogous to (+) @Float
compared to (+) @Int
*)
let rec fib_float n =
let open Float in
match n with
| 0 -> one
| 1 -> one
| n -> fib_float (n - 1) +? fib_float (n - 2)
(*
To write code generic over the number type
analogous to fib :: Num a => Int -> a
we have to use a Functor to let the caller choose our instance.
*)
module Fib =
functor (Num: Number_type) ->
struct
let rec fib n =
let open Num in
match n with
| 0 -> one
| 1 -> one
| n -> fib (n - 1) +? fib (n - 2)
end
let fib4_int = fib_int 4
let fib5_int = let open Fib(Integer) in fib 5
let fib4_float = fib_float 4
let fib5_float = let module FloatFib = Fib(Integer) in FloatFib.fib 5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment