Skip to content

Instantly share code, notes, and snippets.

@brendanzab
Last active November 18, 2024 13:56
Show Gist options
  • Save brendanzab/64afe04fe6ab77c9280545ea32f5e60e to your computer and use it in GitHub Desktop.
Save brendanzab/64afe04fe6ab77c9280545ea32f5e60e to your computer and use it in GitHub Desktop.
Set examples in OCaml based on William R. Cook’s “On Understanding Data Abstraction, Revisited”
(** Set examples in OCaml from {{:https://www.cs.utexas.edu/~wcook/Drafts/2009/essay.pdf}
“On Understanding Data Abstraction, Revisited”} by William R. Cook
*)
(** ADT-style set implementations.
See Section 2 of the paper.
*)
module Abstract_data_types = struct
(** A set encoded using a module. This is the most common and idiomatic
approach used for defining APIs in OCaml. *)
module Module = struct
module Set : sig
type t
val empty : t
val insert : t -> int -> t
val is_empty : t -> bool
val contains : t -> int -> bool
val union : t -> t -> t
end = struct
type t =
| Empty
| Insert of int * t
let empty = Empty
let is_empty s =
s = Empty
let rec contains s i =
match s with
| Empty -> false
| Insert (n, r) ->
if i = n then true else contains r i
let insert s i =
if not (contains s i) then
Insert (i, s)
else s
let rec union s1 s2 =
match s1 with
| Empty -> s2
| Insert (n1, r1) -> insert (union r1 s2) n1
end
(* TODO: Show sorted set implementation *)
end
(** A set that hides its implementation using an existential type. *)
module Existential = struct
type set =
| Set : 'rep. {
empty : 'rep;
insert : 'rep -> int -> 'rep;
is_empty : 'rep -> bool;
contains : 'rep -> int -> bool;
union : 'rep -> 'rep -> 'rep;
} -> set
let set : set =
let empty = [] in
let is_empty s = s = [] in
let rec contains s i =
match s with
| [] -> false
| n :: r ->
if i = n then true else contains r i
in
let insert s i =
if not (contains s i) then i :: s else s
in
let rec union s1 s2 =
match s1 with
| [] -> s2
| n1 :: r1 -> insert (union r1 s2) n1
in
Set { empty; insert; is_empty; contains; union }
end
(* TODO: Show sorted set implementation *)
end
(** Object-oriented set implementations.
See Section 3 of the paper.
*)
module Object_oriented = struct
module Functions = struct
type set = int -> bool
let empty : set = fun _ -> false
let insert (s : set) (n : int) : set = fun i -> i = n || s i
let union (s1 : set) (s2 : set) : set = fun i -> s1 i || s2 i
end
(** Recursive record types *)
module Records = struct
type set = {
is_empty : bool;
contains : int -> bool;
insert : int -> set;
union : set -> set;
}
let rec empty () : set =
let rec self = {
is_empty = true;
contains = (fun _ -> false);
insert = (fun i -> insert self i);
union = (fun s -> s);
} in self
and insert (s : set) (n : int) : set =
if s.contains n then s else
let rec self = {
is_empty = false;
contains = (fun i -> i = n || s.contains i);
insert = (fun i -> insert self i);
union = (fun s -> union self s);
} in self
and union (s1 : set) (s2 : set) : set =
let rec self = {
is_empty = s1.is_empty && s2.is_empty;
contains = (fun i -> s1.contains i || s2.contains i);
insert = (fun i -> insert self i);
union = (fun s -> union self s);
} in self
end
(** Object types and objects *)
module Objects = struct
type set = <
is_empty : bool;
contains : int -> bool;
insert : int -> set;
union : set -> set;
>
let rec empty () : set = object(self)
method is_empty = true
method contains _ = false
method insert i = insert self i
method union s = s
end
and insert (s : set) (n : int) : set =
if s#contains n then s else
object(self)
method is_empty = false
method contains i = (i = n) || s#contains i
method insert i = insert self i
method union s = union self s
end
and union (s1 : set) (s2 : set) : set = object(self)
method is_empty = s1#is_empty && s2#is_empty
method contains i = s1#contains i || s2#contains i
method insert i = insert self i
method union s = union self s
end
end
(** I don't think anyone would usually use first-class modules like this,
but I’m including it to demonstrate the correspondance between modules and
object-oriented approaches to programming. *)
module FirstClassModules = struct
module rec Set : sig
module type S = sig
val is_empty : bool
val contains : int -> bool
val insert : int -> (module Set.S)
val union : (module Set.S) -> (module Set.S)
end
val empty : unit -> (module Set.S)
val insert : (module Set.S) -> int -> (module Set.S)
val union : (module Set.S) -> (module Set.S) -> (module Set.S)
end = struct
include Set
let empty () : (module S) =
let rec self : (module S) = (module struct
let is_empty = true
let contains _ = false
let insert i = insert self i
let union s = s
end) in self
let insert (module S : S) (n : int) : (module S) =
if S.contains n then (module S) else
let rec self : (module S) = (module struct
let is_empty = false
let contains i = (i = n) || S.contains i
let insert i = insert self i
let union s = union self s
end) in self
let union (module S1 : S) (module S2 : S) : (module S) =
let rec self : (module S) = (module struct
let is_empty = S1.is_empty && S2.is_empty
let contains i = S1.contains i || S2.contains i
let insert i = insert self i
let union s = union self s
end) in self
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment