diff --git a/imp.opam b/imp.opam index 57a433e..8ec33e1 100644 --- a/imp.opam +++ b/imp.opam @@ -3,7 +3,7 @@ name: "imp" synopsis: "Experimental library using modular implicits" version: "dev" maintainer: "yallop@gmail.com" -authors: ["Leo White" "Jeremy Yallop"] +authors: ["Leo White" "Jeremy Yallop" "Patrick Reader"] homepage: "https://github.com/modular-implicits/imp" dev-repo: "git+https://github.com/modular-implicits/imp.git" bug-reports: "http://github.com/modular-implicits/imp/issues" diff --git a/lib/any.ml b/lib/any.ml new file mode 100644 index 0000000..6932523 --- /dev/null +++ b/lib/any.ml @@ -0,0 +1,8 @@ +module type Any = sig + type t_for_any +end + +implicit module Any_Int = struct type t_for_any = int end +implicit module Any_String = struct type t_for_any = string end +implicit module Any_List {A : Any} = struct type t_for_any = A.t_for_any list end +implicit module Any_Pair {A : Any} {B : Any} = struct type t_for_any = A.t_for_any * B.t_for_any end diff --git a/lib/control.ml b/lib/control.ml index 6204467..82463fa 100644 --- a/lib/control.ml +++ b/lib/control.ml @@ -1,6 +1,8 @@ -(* Funtor, Applicative and Monad module types *) +open Any + +(* Functor, Applicative and Monad module types *) module type Functor = sig - type 'a t + type +'a t val fmap : ('a -> 'b) -> 'a t -> 'b t end;; @@ -44,12 +46,14 @@ let sequence {M : Monad} (ms : 'a M.t list) = ms (return []) -(* Create a monad using default functor and idiom implementation *) +(* Create a functor, applicative, and monad from just return and bind, + using default functor and applicative implementation *) module Monad(M : sig - type 'a t + type +'a t val return : 'a -> 'a t val bind : 'a t -> ('a -> 'b t) -> 'b t - end) = struct + end): Monad with type 'a t = 'a M.t = struct + type +'a t = 'a M.t (* Functor *) let fmap f m = M.bind m (fun x -> M.return (f x)) (* Applicative *) @@ -62,30 +66,9 @@ module Monad(M : sig let bind = M.bind end;; -(* Monad for option *) -implicit module MonadOption = Monad(struct - type 'a t = 'a option - let return x = Some x - let bind x f = match x with - | None -> None - | Some x -> f x -end);; - -(* Monad for list *) -implicit module MonadList = Monad(struct - type 'a t = 'a list - let return x = [x] - let bind x f = - let rec aux acc = function - | x :: xs -> aux (x @ acc) xs - | [] -> acc - in - aux [] (List.rev_map f x) -end);; - module type Monad_plus = sig include Monad - val mzero : unit -> 'a t + val mzero : 'a t val mplus : 'a t -> 'a t -> 'a t end @@ -97,7 +80,7 @@ module Monad_plus = struct if b then M.return () else - M.mzero () + M.mzero end module type Foldable = sig @@ -119,7 +102,14 @@ module Traversable = struct let traverse {T : Traversable} = T.traverse end -implicit module Option = struct +implicit module Option: sig + include Functor with type 'a t = 'a option + include Applicative with type 'a t := 'a t + include Monad with type 'a t := 'a t + include Monad_plus with type 'a t := 'a t + include Foldable with type 'a t := 'a t + include Traversable with type 'a t := 'a t +end = struct type 'a t = 'a option (* Functor *) @@ -128,13 +118,12 @@ implicit module Option = struct | Some a -> Some (f a) (* Applicative *) - let pure x = Some x + let return x = Some x let apply f x = match f, x with | Some f, Some x -> Some (f x) | _, _ -> None (* Monad *) - let return x = Some x let bind x f = match x with | None -> None | Some x -> f x @@ -150,40 +139,98 @@ implicit module Option = struct | None -> acc | Some x -> f x acc - let traverse (type a) (type b) {F : Applicative} (f : a -> b F.t) : a option -> b t F.t = function + (* Traversable *) + let traverse (type a) (type b) {F : Applicative} (f : a -> b F.t) : a option -> b option F.t = function | None -> F.return None | Some x -> F.fmap (fun x -> Some x) (f x) end -implicit module List = struct +implicit module List : sig + include Functor with type 'a t = 'a list + include Applicative with type 'a t := 'a t + include Monad with type 'a t := 'a t + include Monad_plus with type 'a t := 'a t + include Foldable with type 'a t := 'a t + include Traversable with type 'a t := 'a t +end = struct type 'a t = 'a list (* Functor *) let fmap = List.map - (* Monad *) + (* Applicative *) let return x = [x] - let bind x f = - let rec aux acc = function - | x :: xs -> aux (x @ acc) xs - | [] -> acc in - aux [] (List.rev_map f x) + let apply fs xs = + List.concat (List.map (fun f -> List.map (fun x -> f x) xs) fs) - (* Applicative *) - let pure x = [x] - let apply fs xs = bind fs (bind xs) + (* Monad *) + let bind x f = List.concat (List.map f x) (* Monad_plus *) let mzero = [] let mplus = (@) (* Foldable *) - let rec fold f t acc = match t with - | [] -> acc - | x :: xs -> fold f xs (f x acc) + let fold f xs a = List.fold_left (fun x y -> f y x) a xs (* Traversable *) let traverse {F : Applicative} f t = - let cons x ys = F.apply (F.apply (F.return (fun x xs -> x :: xs)) (f x)) ys in - fold cons t (F.return []) + let cons x ys = F.apply (F.fmap (fun x xs -> x :: xs) (f x)) ys in + List.fold_right cons t (F.return []) +end + +implicit module Function {A : Any} : sig + include Functor with type 'b t = A.t_for_any -> 'b + include Applicative with type 'b t := 'b t + include Monad with type 'b t := 'b t +end = struct + type 'b t = A.t_for_any -> 'b + + (* Functor *) + let fmap m f x = m (f x) + + (* Applicative *) + let return x _ = x + let apply f g x = f x (g x) + + (* Monad *) + let bind g f x = f (g x) x +end +(** (a -> b) is an instance of Monad b - it behaves like the reader monad *) + +implicit module Pair {A : Any} : Functor with type 'b t = A.t_for_any * 'b = struct + type 'b t = A.t_for_any * 'b + + let fmap m (a, b) = (a, m b) +end + +type ('a, 'b) const = Const of 'a + +implicit module Const {A : Any}: sig + include Functor with type 'b t = (A.t_for_any, 'b) const +end = struct + type 'b t = (A.t_for_any, 'b) const + let fmap _ (Const x) = (Const x) +end + +implicit module Const_Applicative {A: Data.Monoid}: Applicative with type 'b t = (A.t, 'b) const += struct + type 'b t = (A.t, 'b) const + let fmap _ (Const x) = (Const x) + let return _ = Const (Data.Monoid.empty ()) + let apply (Const a) (Const a') = Const (Data.Monoid.append a a') +end + +type 'b identity = Identity of 'b + +implicit module Identity: sig + include Functor with type 'b t = 'b identity + include Applicative with type 'b t := 'b t + include Monad with type 'b t := 'b t +end = struct + type 'b t = 'b identity + let fmap f (Identity b) = Identity (f b) + let return b = Identity b + let apply (Identity f) (Identity x) = Identity (f x) + let bind (Identity x) f = f x end diff --git a/lib/data.ml b/lib/data.ml index a88407a..f2607d8 100644 --- a/lib/data.ml +++ b/lib/data.ml @@ -1,19 +1,4 @@ -module type Any = sig - type t -end - -module type Show = sig - type t - val to_string: t -> string - val buffer_add : Buffer.t -> t -> unit - val pp_print : Format.formatter -> t -> unit -end - -module Show = struct - let to_string {M : Show} = M.to_string - let buffer_add {M : Show} = M.buffer_add - let pp_print {M : Show} = M.pp_print -end +open Any module type Eq = sig type t @@ -24,18 +9,25 @@ module Eq = struct let ( = ) {M : Eq} = M.(=) end +type ordering = LT | GT | EQ + module type Ord = sig type t - val compare : t -> t -> int + val compare : t -> t -> ordering end module Ord = struct - let ( = ) {M : Ord} a b = M.compare a b = 0 - let ( <> ) {M : Ord} a b = M.compare a b <> 0 - let ( < ) {M : Ord} a b = M.compare a b < 0 - let ( <= ) {M : Ord} a b = M.compare a b <= 0 - let ( > ) {M : Ord} a b = M.compare a b > 0 - let ( >= ) {M : Ord} a b = M.compare a b >= 0 + let translateCompare (compare : 'a -> 'a -> int) = + fun x y -> let n = compare x y in + if n < 0 then LT + else if n = 0 then EQ + else (* if n > 0 then *) GT + let ( < ) {M : Ord} a b = M.compare a b = LT + let ( <= ) {M : Ord} a b = M.compare a b <> GT + let ( > ) {M : Ord} a b = M.compare a b = GT + let ( >= ) {M : Ord} a b = M.compare a b <> LT + let ( = ) {M : Ord} a b = M.compare a b = EQ + let ( <> ) {M : Ord} a b = M.compare a b <> EQ let compare {M : Ord} = M.compare end @@ -84,7 +76,7 @@ module Enum = struct let rec fold_enum_to : {M : Enum} -> M.t -> M.t -> (M.t -> 'a -> 'a) -> 'a -> 'a = fun {M : Enum} a b f acc -> - if M.compare a b < 0 then + if M.compare a b = LT then fold_enum_to (M.succ a) b f (f a acc) else acc @@ -92,7 +84,7 @@ module Enum = struct let rec fold_enum_downto : {M : Enum} -> M.t -> M.t -> (M.t -> 'a -> 'a) -> 'a -> 'a = fun {M : Enum} a b f acc -> - if M.compare b a < 0 then + if M.compare b a = LT then fold_enum_downto (M.pred a) b f (f a acc) else acc @@ -117,19 +109,20 @@ end (* Instances *) -implicit module Int = struct +implicit module Int: sig + include Eq with type t = int + include Ord with type t := t + include Num with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct type t = int - (* Show *) - let to_string = string_of_int - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print = Format.pp_print_int - (* Eq *) let ( = ) (a : int) b = a = b (* Ord *) - let compare (a : int) b = compare a b + let compare (a : int) b = Ord.translateCompare compare a b (* Num *) let zero = 0 @@ -147,25 +140,21 @@ implicit module Int = struct (* Enum *) let succ = succ let pred = pred - - (* Monoid, addition *) - let empty = 0 - let append = (+) end -implicit module Float = struct +implicit module Float: sig + include Eq with type t = float + include Ord with type t := t + include Num with type t := t + include Bounded with type t := t +end = struct type t = float - (* Show *) - let to_string = string_of_float - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print = Format.pp_print_float - (* Eq *) let ( = ) (a : float) b = a = b (* Ord *) - let compare (a : float) b = compare a b + let compare (a : float) b = Ord.translateCompare compare a b (* Num *) let zero = 0. @@ -179,28 +168,24 @@ implicit module Float = struct (* Bounded *) let bounds = (neg_infinity, infinity) - - (* Monoid, addition *) - let empty = 0. - let append = (+.) end -implicit module Bool = struct +implicit module Bool: sig + include Eq with type t = bool + include Ord with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct type t = bool - (* Show *) - let to_string = string_of_bool - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print = Format.pp_print_bool - (* Eq *) let ( = ) (a : bool) b = a = b (* Ord *) - let compare (a : bool) b = compare a b + let compare (a : bool) b = Ord.translateCompare compare a b (* Bounded *) - let bounds = (neg_infinity, infinity) + let bounds = (false, true) (* Enum *) let succ = function @@ -210,25 +195,21 @@ implicit module Bool = struct let pred = function | true -> false | false -> invalid_arg "Bool.pred" - - (* Monoid, addition *) - let empty = false - let append = (||) end -implicit module Char = struct +implicit module Char: sig + include Eq with type t = char + include Ord with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct type t = char - (* Show *) - let to_string c = String.escaped (String.make 1 c) - let buffer_add b c = Buffer.add_string b (to_string c) - let pp_print ppf c = Format.pp_print_string ppf c - (* Eq *) let ( = ) (a : char) b = a = b (* Ord *) - let compare (a : char) b = compare a b + let compare (a : char) b = Ord.translateCompare compare a b (* Bounded *) let bounds = ('\000', '\255') @@ -243,38 +224,46 @@ implicit module Char = struct | n -> Char.chr (pred (Char.code n)) end -implicit module String = struct +implicit module String: sig + include Eq with type t = string + include Ord with type t := t + include Monoid with type t := t +end = struct type t = string - (* Show *) - let to_string = String.escaped - let buffer_add b s = Buffer.add_string b (to_string s) - let pp_print ppf s = Format.pp_print_string ppf (to_string s) - (* Eq *) let ( = ) (a : string) b = a = b (* Ord *) - let compare (a : string) b = compare a b + let compare (a : string) b = Ord.translateCompare compare a b (* Monoid *) let empty = "" let append = (^) end -implicit module Int32 = struct - type t = int32 +module List {A : Any} : Monoid with type t = A.t_for_any list = struct + type t = A.t_for_any list + + (* Monoid *) + let empty = [] + let append = (@) +end - (* Show *) - let to_string = Int32.to_string - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print ppf s = Format.pp_print_string ppf (to_string s) +implicit module Int32: sig + include Eq with type t = int32 + include Ord with type t := t + include Num with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct + type t = int32 (* Eq *) let ( = ) (a : int32) b = a = b (* Ord *) - let compare = Int32.compare + let compare a b = Ord.translateCompare Int32.compare a b (* Num *) let zero = 0l @@ -292,25 +281,22 @@ implicit module Int32 = struct (* Enum *) let succ = Int32.succ let pred = Int32.pred - - (* Monoid, addition *) - let empty = 0l - let append = Int32.add end -implicit module Int64 = struct +implicit module Int64: sig + include Eq with type t = int64 + include Ord with type t := t + include Num with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct type t = int64 - (* Show *) - let to_string = Int64.to_string - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print ppf i = Format.pp_print_string ppf (to_string i) - (* Eq *) let ( = ) (a : int64) b = a = b (* Ord *) - let compare = Int64.compare + let compare a b = Ord.translateCompare Int64.compare a b (* Num *) let zero = 0L @@ -328,29 +314,26 @@ implicit module Int64 = struct (* Enum *) let succ = Int64.succ let pred = Int64.pred - - (* Monoid, addition *) - let empty = 0L - let append = Int64.add end -implicit module Nativeint = struct +implicit module Nativeint: sig + include Eq with type t = nativeint + include Ord with type t := t + include Num with type t := t + include Bounded with type t := t + include Enum with type t := t +end = struct type t = nativeint - (* Show *) - let to_string = Nativeint.to_string - let buffer_add b i = Buffer.add_string b (to_string i) - let pp_print ppf i = Format.pp_print_string ppf (to_string i) - (* Eq *) let ( = ) (a : nativeint) b = a = b (* Ord *) - let compare = Nativeint.compare + let compare a b = Ord.translateCompare Nativeint.compare a b (* Num *) - let zero = 0L - let one = 1L + let zero = Nativeint.of_int 0 + let one = Nativeint.of_int 1 let of_int = Nativeint.of_int let ( + ) = Nativeint.add let ( - ) = Nativeint.sub @@ -364,8 +347,12 @@ implicit module Nativeint = struct (* Enum *) let succ = Nativeint.succ let pred = Nativeint.pred +end + +implicit module Unit: Monoid with type t = unit = struct + type t = unit - (* Monoid, addition *) - let empty = 0L - let append = Nativeint.add + (* Monoid *) + let empty = () + let append () () = () end diff --git a/lib/dune b/lib/dune index 682db47..adc2f06 100644 --- a/lib/dune +++ b/lib/dune @@ -1,4 +1,4 @@ (library (public_name imp) - (modules Control Data Num Scope Show) + (modules Any Control Data Scope Show) (synopsis "Experimental library using modular implicits")) diff --git a/lib/num.ml b/lib/num.ml deleted file mode 100644 index 602cbf9..0000000 --- a/lib/num.ml +++ /dev/null @@ -1,42 +0,0 @@ -module type Num = sig - type t - val ( + ) : t -> t -> t - val ( - ) : t -> t -> t - val ( * ) : t -> t -> t - val ( / ) : t -> t -> t - val (~- ) : t -> t - val zero : t - val one : t - val of_int : int -> t -end;; - -module Num = struct - let ( + ) {M : Num} = M.( + ) - let ( - ) {M : Num} = M.( - ) - let ( * ) {M : Num} = M.( * ) - let ( / ) {M : Num} = M.( / ) - let (~- ) {M : Num} = M.(~- ) - let zero {M : Num} () = M.zero - let one {M : Num} () = M.one - let (~~) {M : Num} = M.of_int -end;; - -implicit module Int = struct - type t = int - let ( + ),( - ),( * ), ( / ), (~- ) - = ( + ),( - ),( * ), ( / ), (~- ) - let zero = 0 - let one = 1 - let of_int x = x -end;; - -implicit module Float = struct - type t = float - let ( + ), ( - ), ( * ), ( / ), ( ~- ) - = ( +. ), ( -. ), ( *. ), ( /. ), ( ~-. ) - let zero = 0. - let one = 1. - let of_int = float_of_int - let ( = ), ( <> ), ( < ), ( <= ), ( > ), ( >= ) - = ( = ), ( <> ), ( < ), ( <= ), ( > ), ( >= ) -end;; diff --git a/lib/show.ml b/lib/show.ml index 11c82e9..8839fb2 100644 --- a/lib/show.ml +++ b/lib/show.ml @@ -15,6 +15,11 @@ implicit module ShowString = struct let show = Printf.sprintf "%S" end;; +implicit module ShowBool = struct + type t = bool + let show = Printf.sprintf "%b" +end;; + implicit module ShowInt = struct type t = int let show = string_of_int @@ -34,3 +39,38 @@ implicit module ShowPair {A : Show} {B : Show} = struct type t = A.t * B.t let show (a, b) = "(" ^ A.show a ^ ", " ^ B.show b ^ ")" end;; + +implicit module ShowUnit = struct + type t = unit + let show () = "()" +end;; + +implicit module Show3Tuple {A : Show} {B : Show} {C : Show} = struct + type t = A.t * B.t * C.t + let show (a, b, c) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ")" +end + +implicit module Show4Tuple {A : Show} {B : Show} {C : Show} {D : Show} = struct + type t = A.t * B.t * C.t * D.t + let show (a, b, c, d) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ", " ^ D.show d ^ ")" +end + +implicit module Show5Tuple {A : Show} {B : Show} {C : Show} {D : Show} {E : Show} = struct + type t = A.t * B.t * C.t * D.t * E.t + let show (a, b, c, d, e) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ", " ^ D.show d ^ ", " ^ E.show e ^ ")" +end + +implicit module Show6Tuple {A : Show} {B : Show} {C : Show} {D : Show} {E : Show} {F : Show} = struct + type t = A.t * B.t * C.t * D.t * E.t * F.t + let show (a, b, c, d, e, f) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ", " ^ D.show d ^ ", " ^ E.show e ^ ", " ^ F.show f ^ ")" +end + +implicit module Show7Tuple {A : Show} {B : Show} {C : Show} {D : Show} {E : Show} {F : Show} {G : Show} = struct + type t = A.t * B.t * C.t * D.t * E.t * F.t * G.t + let show (a, b, c, d, e, f, g) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ", " ^ D.show d ^ ", " ^ E.show e ^ ", " ^ F.show f ^ ", " ^ G.show g ^ ")" +end + +implicit module Show8Tuple {A : Show} {B : Show} {C : Show} {D : Show} {E : Show} {F : Show} {G : Show} {H : Show} = struct + type t = A.t * B.t * C.t * D.t * E.t * F.t * G.t * H.t + let show (a, b, c, d, e, f, g, h) = "(" ^ A.show a ^ ", " ^ B.show b ^ ", " ^ C.show c ^ ", " ^ D.show d ^ ", " ^ E.show e ^ ", " ^ F.show f ^ ", " ^ G.show g ^ ", " ^ H.show h ^ ")" +end diff --git a/tests/test.ml b/tests/test.ml index 3f633de..217ee9c 100644 --- a/tests/test.ml +++ b/tests/test.ml @@ -1,13 +1,12 @@ - let () = - let open Imp.Num.Num in - let open implicit Imp.Num in + let open Imp.Data.Num in + let open implicit Imp.Data in begin let x = 1 + one() + one() in assert (x = 3); let y = 2.5 + 6.0 in assert (y = 8.5); - let sq {N : Imp.Num.Num} (x : N.t) = x * x in + let sq {N : Imp.Data.Num} (x : N.t) = x * x in let z = sq 6.0 in assert (z = 36.0); end @@ -33,3 +32,59 @@ let () = assert (show (4.5, ([9; 10; 11], "hello")) = "(4.5, ([9; 10; 11], \"hello\"))"); end + +let () = + let open Imp.Data in + let e : unit = Monoid.empty () in + assert (Monoid.append e e = ()) + +let () = + let open Imp.Data in + let e : string = Monoid.empty () in + assert (e = ""); + assert (Monoid.append "abc" "def" = "abcdef") + +let () = + let open Imp.Any in + let open Imp.Data in + let e : int list = Monoid.empty {List {Any_Int}} () in + assert (e = []); + assert (Monoid.append {List {Any_Int}} [1; 2] [3] = [1; 2; 3]) + +let () = + let open Imp.Control in + assert (fmap (fun x -> x + 1) [1; 2; 3] = [2; 3; 4]); + assert (return 5 = [5]); + assert (apply [( * ) 2; ( * ) 3] [1; 2; 3] = [2; 4; 6; 3; 6; 9]); + assert (bind [1; 2; 3] (fun x -> [x; x * 2]) = [1; 2; 2; 4; 3; 6]); + assert (Foldable.fold ( * ) [2; 3; 3; 7] 1 = 126); + assert (Traversable.traverse (fun x -> Some (x + 1)) [1; 2; 3] = Some [2; 3; 4]) + (* let sequence {F : Applicative} {T : Traversable} = T.traverse {F} (fun x -> x) in *) + (* assert (sequence {List} {Option} [Some 1; Some 2; Some 3] = Some [1; 2; 3]) *) + +let () = + let open Imp.Control in + assert (fmap (fun x -> x + 1) (Some 3) = (Some 4)); + assert (return 5 = Some 5); + assert (apply (Some (fun x -> x + 1)) (Some 3) = (Some 4)); + assert (apply None (Some 3) = None); + assert (apply (Some (fun x -> x + 1)) None = None); + assert (bind (Some 3) (fun x -> Some (x + 1)) = Some 4); + assert (bind (Some 3) (fun _ -> None) = None); + assert (Foldable.fold ( * ) (Some 5) 1 = 5); + assert (Foldable.fold ( * ) None 1234 = 1234); + assert (Traversable.traverse (fun x -> [x; x + 1]) (Some 3) = [Some 3; Some 4]) + +let () = + let open Imp.Control in + let open implicit Imp.Any in + let pair x y = (x, y) in + assert ((fmap (fun x -> x + 1) (int_of_string)) "3" = 4); + assert ((return 4) "3" = 4); + assert ((apply pair (fun x -> x * x)) 3 = (3, 9)); + assert ((bind (fun x -> x * x) pair) 3 = (9, 3)) + +let () = + let open Imp.Control in + let open implicit Imp.Any in + assert (fmap (fun x -> x + 1) ("hello", 3) = ("hello", 4))