Skip to content

Instantly share code, notes, and snippets.

@ebresafegaga
Created December 20, 2020 11:56
Show Gist options
  • Save ebresafegaga/00f84e41f8731e09f6789d86ca73db8e to your computer and use it in GitHub Desktop.
Save ebresafegaga/00f84e41f8731e09f6789d86ca73db8e to your computer and use it in GitHub Desktop.
Encoding existential types in OCaml with universal types
(* A stack with an existential/abstract type 't *)
type 'a stack =
Stack: { to_list: 't -> 'a list;
of_list: 'a list -> 't;
empty: 't;
push: 'a -> 't -> 't;
pop: 't -> ('t * 'a) option } ->
'a stack
let stackInstance =
Stack { to_list = Fun.id;
of_list = Fun.id;
empty = [];
push = (fun x xs -> x :: xs);
pop = function [] -> None | x :: xs -> Some (xs, x) }
let test () =
let Stack {of_list; to_list; empty; push; pop} = stackInstance in
let e = empty |> push 29 |> push 34 |> push 78 in
let v =
match pop e with
| None -> 0
| Some (_, x) -> x
in
to_list e
(* OCaml has polymorphic records, which can be used to emulate higher-rank polymorphism (RankNTypes) *)
(* We will now use it to encode existential types *)
(* 't is the abstract type, 'b is the element of the stack,
'a is the result of computation that uses the stack *)
type 'b uniStack = { ff: 'a. ('a, 'b) inner -> 'a }
and ('a, 'b) inner = {f: 't. to_list:('t -> 'b list) ->
of_list:('b list -> 't) ->
empty:'t ->
push:('b -> 't -> 't) ->
pop:('t -> ('t * 'b) option) -> 'a }
let uniStackInstance =
{ ff = fun {f} -> f ~to_list:Fun.id ~of_list:Fun.id
~empty:[]
~push:(fun x xs -> x :: xs)
~pop:(function [] -> None | x :: xs -> Some (xs, x)) }
let test () =
let {ff} = uniStackInstance in
ff { f = fun ~to_list ~of_list ~empty ~push ~pop ->
let n = empty |> push 45 in
let b = of_list [2;4;4] in
let c = to_list b in
pop b
|> Fun.flip Option.bind (fun (_, v) -> Some (v + 1))
|> Option.value ~default:56 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment