module type Functor = sig type 'a t val map : ('a -> 'b) -> 'a t -> 'b t end module type Applicative = sig type 'a t val pure : 'a -> 'a t val apply : ('a -> 'b) t -> 'a t -> 'b t end module type Monad = sig type 'a t val return : 'a -> 'a t val bind : ('a -> 'b t) -> 'a t -> 'b t end module ApplicativeOfMonad (M : Monad) : Applicative with type 'a t = 'a M.t = struct type 'a t = 'a M.t let pure = M.return let apply f x = M.(bind (fun y -> bind (fun g -> return (g y)) f) x) end module FunctorOfApplicative (A : Applicative) : Functor with type 'a t = 'a A.t = struct type 'a t = 'a A.t let map f x = A.(apply (pure f) x) end module FunctorOfMonad (M : Monad) : Functor with type 'a t = 'a M.t = struct include FunctorOfApplicative(ApplicativeOfMonad(M)) end module MonadDerive (M : Monad) = struct include M include ApplicativeOfMonad(M) include FunctorOfMonad(M) let (>>=) x f = bind f x let (<$>) x f = map x f let (<*>) x f = apply x f end module ListMonad = struct type 'a t = 'a list let return x = [x] let rec bind (f : 'a -> 'b list) : 'a list -> 'b list = function | [] -> [] | x :: xs -> f x @ bind f xs end module Dlm = MonadDerive(ListMonad) let pair x y = x, y let cart_prod xs ys = Dlm.(pair <$> xs <*> ys) let () = cart_prod [1;2;3;4] ["7"; "hello there"; "forthwith!"] |> List.iter (fun (x, y) -> print_endline @@ "(" ^ string_of_int x ^ ", " ^ y ^ ")") (* ============================================================================================= *) module StateMonad (S : sig type t end) = struct type 'a t = S.t -> S.t * 'a let return x s = (s, x) let bind f x s = let s', a = x s in f a s' end module IntStateMonad = StateMonad(struct type t = int end)