mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-08 12:15:32 -05:00
164 lines
4.2 KiB
OCaml
164 lines
4.2 KiB
OCaml
|
|
module type MONAD = sig
|
|
type 'a t
|
|
val return : 'a -> 'a t
|
|
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
|
|
end
|
|
|
|
module NonLogical = struct
|
|
type 'a t = unit -> 'a
|
|
let return x () = x
|
|
let (>>=) x f () = let y = x() in f y ()
|
|
end
|
|
|
|
type ('a, 'b) list_view =
|
|
| Nil of exn
|
|
| Cons of 'a * 'b
|
|
|
|
(** The monad is parametrised in the types of state, environment and
|
|
writer. *)
|
|
module type Param = sig
|
|
(** Read only *)
|
|
type e
|
|
(** Write only *)
|
|
type w
|
|
(** [w] must be a monoid *)
|
|
val wunit : w
|
|
val wprod : w -> w -> w
|
|
(** Read-write *)
|
|
type s
|
|
(** Update-only. Essentially a writer on [u->u]. *)
|
|
type u
|
|
(** [u] must be pointed. *)
|
|
val uunit : u
|
|
end
|
|
|
|
module Logical (P:Param) = struct
|
|
type state = {
|
|
e: P.e;
|
|
w: P.w;
|
|
s: P.s;
|
|
u: P.u;
|
|
}
|
|
|
|
type _ t =
|
|
| Ignore : _ t -> unit t
|
|
| Return : 'a -> 'a t
|
|
| Bind : 'a t * ('a -> 'b t) -> 'b t
|
|
| Map : 'a t * ('a -> 'b) -> 'b t
|
|
| Get : P.s t
|
|
| Set : P.s -> unit t
|
|
| Modify : (P.s -> P.s) -> unit t
|
|
| Put : P.w -> unit t
|
|
| Current : P.e t
|
|
| Local : P.e * 'a t -> 'a t (* local bind *)
|
|
| Update : (P.u -> P.u) -> unit t
|
|
| Zero : exn -> 'a t
|
|
| WithState : state * 'a t -> 'a t (* use other state *)
|
|
| Plus : 'a t * (exn -> 'a t ) -> 'a t
|
|
| Split : 'a t -> ('a, exn -> 'a t) list_view t
|
|
| Once : 'a t -> 'a t (* keep at most one element *)
|
|
| Break : (exn -> exn option) * 'a t -> 'a t
|
|
|
|
let return x = Return x
|
|
let (>>=) x f = Bind (x, f)
|
|
let map f x = Map (x, f)
|
|
let ignore x = Ignore x
|
|
let set x = Set x
|
|
let get = Get
|
|
let modify f = Modify f
|
|
let put x = Put x
|
|
let current = Current
|
|
let local x y = Local (x, y)
|
|
let update f = Update f
|
|
let zero e = Zero e
|
|
let with_state st x = WithState (st, x)
|
|
let plus a f = Plus (a, f)
|
|
let split x = Split x
|
|
let once x = Once x
|
|
let break f x = Break (f, x)
|
|
|
|
type 'a reified =
|
|
| RNil of exn
|
|
| RCons of 'a * (exn -> 'a reified)
|
|
|
|
let repr r () = match r with
|
|
| RNil e -> Nil e
|
|
| RCons (x, f) -> Cons (x, f)
|
|
|
|
let cons x cont = Cons (x, cont)
|
|
let nil e = Nil e
|
|
|
|
let rcons x cont = RCons (x, cont)
|
|
let rnil e = RNil e
|
|
|
|
type 'a splitted = (('a * state), exn -> 'a t) list_view
|
|
|
|
let rec run_rec
|
|
: type a. state -> a t -> a splitted
|
|
= fun st t -> match t with
|
|
| Return x -> cons (x, st) zero
|
|
| Ignore x ->
|
|
begin match run_rec st x with
|
|
| Nil e -> Nil e
|
|
| Cons ((_, st), cont) -> cons ((), st) (fun e -> Ignore (cont e))
|
|
end
|
|
| Bind (x,f) ->
|
|
begin match run_rec st x with
|
|
| Nil e -> Nil e
|
|
| Cons ((x, st_x), cont) ->
|
|
let y = f x in
|
|
run_rec st_x (plus y (fun e -> with_state st (cont e >>= f)))
|
|
end
|
|
| Map (x,f) ->
|
|
begin match run_rec st x with
|
|
| Nil e -> Nil e
|
|
| Cons ((x, st), cont) ->
|
|
cons (f x, st) (fun e -> map f (cont e))
|
|
end
|
|
| Get -> cons (st.s, st) zero
|
|
| Set s -> cons ((), {st with s}) zero
|
|
| Modify f ->
|
|
let st = {st with s = f st.s} in
|
|
cons ((), st) zero
|
|
| Put w -> cons ((), {st with w}) zero
|
|
| Current -> cons (st.e, st) zero
|
|
| Local (e,x) ->
|
|
(* bind [st.e = e] in [x] *)
|
|
let st' = {st with e} in
|
|
run_rec st' x
|
|
| Update f ->
|
|
let st = {st with u=f st.u} in
|
|
cons ((), st) zero
|
|
| WithState (st', x) -> run_rec st' x (* ignore [st] *)
|
|
| Zero e -> Nil e (* failure *)
|
|
| Plus (x,cont) ->
|
|
begin match run_rec st x with
|
|
| Nil e -> run_rec st (cont e)
|
|
| Cons ((x, st), cont') ->
|
|
cons (x, st) (fun e -> plus (cont' e) cont)
|
|
end
|
|
| Split x ->
|
|
begin match run_rec st x with
|
|
| Nil e -> cons (Nil e, st) zero
|
|
| Cons ((x, st'), cont) -> cons (cons x cont, st') zero
|
|
end
|
|
| Once x ->
|
|
begin match run_rec st x with
|
|
| Nil e -> Nil e
|
|
| Cons ((x, st), _) -> cons (x, st) zero
|
|
end
|
|
| Break (f,x) -> assert false (* TODO: ? *)
|
|
|
|
let run t e s =
|
|
let state = {e; s; u=P.uunit; w=P.wunit} in
|
|
let rec run_list
|
|
: type a. state -> a t -> (a * state) reified
|
|
= fun state t -> match run_rec state t with
|
|
| Nil e -> rnil e
|
|
| Cons ((x, st), cont) ->
|
|
rcons (x, st) (fun e -> run_list state (cont e))
|
|
in
|
|
run_list state t
|
|
end
|
|
|