224 lines
4.6 KiB
OCaml
224 lines
4.6 KiB
OCaml
|
|
open! Import
|
||
|
|
include Either_intf
|
||
|
|
module List = List0
|
||
|
|
include Either0
|
||
|
|
|
||
|
|
let swap = function
|
||
|
|
| First x -> Second x
|
||
|
|
| Second x -> First x
|
||
|
|
;;
|
||
|
|
|
||
|
|
let is_first = function
|
||
|
|
| First _ -> true
|
||
|
|
| Second _ -> false
|
||
|
|
;;
|
||
|
|
|
||
|
|
let is_second = function
|
||
|
|
| First _ -> false
|
||
|
|
| Second _ -> true
|
||
|
|
;;
|
||
|
|
|
||
|
|
let value (First x | Second x) = x
|
||
|
|
|
||
|
|
let value_map t ~first ~second =
|
||
|
|
match t with
|
||
|
|
| First x -> first x
|
||
|
|
| Second x -> second x
|
||
|
|
;;
|
||
|
|
|
||
|
|
let iter = value_map
|
||
|
|
|
||
|
|
let map t ~first ~second =
|
||
|
|
match t with
|
||
|
|
| First x -> First (first x)
|
||
|
|
| Second x -> Second (second x)
|
||
|
|
;;
|
||
|
|
|
||
|
|
let first x = First x
|
||
|
|
let second x = Second x
|
||
|
|
|
||
|
|
let equal eq1 eq2 t1 t2 =
|
||
|
|
match t1, t2 with
|
||
|
|
| First x, First y -> eq1 x y
|
||
|
|
| Second x, Second y -> eq2 x y
|
||
|
|
| First _, Second _ | Second _, First _ -> false
|
||
|
|
;;
|
||
|
|
|
||
|
|
let local_equal eq1 eq2 t1 t2 =
|
||
|
|
match t1, t2 with
|
||
|
|
| First x, First y -> eq1 x y
|
||
|
|
| Second x, Second y -> eq2 x y
|
||
|
|
| First _, Second _ | Second _, First _ -> false
|
||
|
|
;;
|
||
|
|
|
||
|
|
let invariant f s = function
|
||
|
|
| First x -> f x
|
||
|
|
| Second y -> s y
|
||
|
|
;;
|
||
|
|
|
||
|
|
module Focus = struct
|
||
|
|
type ('a, 'b) t =
|
||
|
|
| Focus of { value : 'a }
|
||
|
|
| Other of { value : 'b }
|
||
|
|
end
|
||
|
|
|
||
|
|
module Make_focused (M : sig
|
||
|
|
type (+'a, +'b) t
|
||
|
|
|
||
|
|
val return : 'a -> ('a, _) t
|
||
|
|
val other : 'b -> (_, 'b) t
|
||
|
|
val focus : ('a, 'b) t -> ('a, 'b) Focus.t
|
||
|
|
|
||
|
|
val combine
|
||
|
|
: ('a, 'd) t
|
||
|
|
-> ('b, 'd) t
|
||
|
|
-> f:('a -> 'b -> 'c)
|
||
|
|
-> other:('d -> 'd -> 'd)
|
||
|
|
-> ('c, 'd) t
|
||
|
|
|
||
|
|
val bind : ('a, 'b) t -> f:('a -> ('c, 'b) t) -> ('c, 'b) t
|
||
|
|
end) =
|
||
|
|
struct
|
||
|
|
include M
|
||
|
|
open With_return
|
||
|
|
|
||
|
|
let map t ~f =
|
||
|
|
let res = bind t ~f:(fun x -> return (f x)) in
|
||
|
|
res
|
||
|
|
;;
|
||
|
|
|
||
|
|
include Monad.Make2_local (struct
|
||
|
|
type nonrec ('a, 'b) t = ('a, 'b) t
|
||
|
|
|
||
|
|
let return = return
|
||
|
|
let bind = bind
|
||
|
|
let map = `Custom map
|
||
|
|
end)
|
||
|
|
|
||
|
|
module App = Applicative.Make2_using_map2_local (struct
|
||
|
|
type nonrec ('a, 'b) t = ('a, 'b) t
|
||
|
|
|
||
|
|
let return = return
|
||
|
|
let map = `Custom map
|
||
|
|
|
||
|
|
let map2 : ('a, 'x) t -> ('b, 'x) t -> f:('a -> 'b -> 'c) -> ('c, 'x) t =
|
||
|
|
fun t1 t2 ~f ->
|
||
|
|
bind t1 ~f:(fun x -> bind t2 ~f:(fun y -> return (f x y)) [@nontail]) [@nontail]
|
||
|
|
;;
|
||
|
|
end)
|
||
|
|
|
||
|
|
include App
|
||
|
|
|
||
|
|
let combine_all =
|
||
|
|
let rec other_loop f acc = function
|
||
|
|
| [] -> other acc
|
||
|
|
| t :: ts ->
|
||
|
|
(match focus t with
|
||
|
|
| Focus _ -> other_loop f acc ts
|
||
|
|
| Other o -> other_loop f (f acc o.value) ts)
|
||
|
|
in
|
||
|
|
let rec return_loop f acc = function
|
||
|
|
| [] -> return (List.rev acc)
|
||
|
|
| t :: ts ->
|
||
|
|
(match focus t with
|
||
|
|
| Focus x -> return_loop f (x.value :: acc) ts
|
||
|
|
| Other o -> other_loop f o.value ts)
|
||
|
|
in
|
||
|
|
fun ts ~f -> return_loop f [] ts
|
||
|
|
;;
|
||
|
|
|
||
|
|
let combine_all_unit =
|
||
|
|
let rec other_loop f acc = function
|
||
|
|
| [] -> other acc
|
||
|
|
| t :: ts ->
|
||
|
|
(match focus t with
|
||
|
|
| Focus _ -> other_loop f acc ts
|
||
|
|
| Other o -> other_loop f (f acc o.value) ts)
|
||
|
|
in
|
||
|
|
let rec return_loop f = function
|
||
|
|
| [] -> return ()
|
||
|
|
| t :: ts ->
|
||
|
|
(match focus t with
|
||
|
|
| Focus { value = () } -> return_loop f ts
|
||
|
|
| Other { value = o } -> other_loop f o ts)
|
||
|
|
in
|
||
|
|
fun ts ~f -> return_loop f ts
|
||
|
|
;;
|
||
|
|
|
||
|
|
let to_option t =
|
||
|
|
match focus t with
|
||
|
|
| Focus x -> Some x.value
|
||
|
|
| Other _ -> None
|
||
|
|
;;
|
||
|
|
|
||
|
|
let value t ~default =
|
||
|
|
match focus t with
|
||
|
|
| Focus x -> x.value
|
||
|
|
| Other _ -> default
|
||
|
|
;;
|
||
|
|
|
||
|
|
let with_return f =
|
||
|
|
with_return (fun ret -> other (f (With_return.prepend ret ~f:return))) [@nontail]
|
||
|
|
;;
|
||
|
|
end
|
||
|
|
|
||
|
|
module First = Make_focused (struct
|
||
|
|
type nonrec ('a, 'b) t = ('a, 'b) t
|
||
|
|
|
||
|
|
let return = first
|
||
|
|
let other = second
|
||
|
|
|
||
|
|
let focus t : _ Focus.t =
|
||
|
|
match t with
|
||
|
|
| First x -> Focus { value = x }
|
||
|
|
| Second y -> Other { value = y }
|
||
|
|
;;
|
||
|
|
|
||
|
|
let combine t1 t2 ~f ~other =
|
||
|
|
match t1, t2 with
|
||
|
|
| First x, First y -> First (f x y)
|
||
|
|
| Second x, Second y -> Second (other x y)
|
||
|
|
| Second x, _ | _, Second x -> Second x
|
||
|
|
;;
|
||
|
|
|
||
|
|
let bind t ~f =
|
||
|
|
match t with
|
||
|
|
| First x -> f x
|
||
|
|
(* Reuse the value in order to avoid allocation. *)
|
||
|
|
| Second _ as y -> y
|
||
|
|
;;
|
||
|
|
end)
|
||
|
|
|
||
|
|
module Second = Make_focused (struct
|
||
|
|
type nonrec ('a, 'b) t = ('b, 'a) t
|
||
|
|
|
||
|
|
let return = second
|
||
|
|
let other = first
|
||
|
|
|
||
|
|
let focus t : _ Focus.t =
|
||
|
|
match t with
|
||
|
|
| Second x -> Focus { value = x }
|
||
|
|
| First y -> Other { value = y }
|
||
|
|
;;
|
||
|
|
|
||
|
|
let combine t1 t2 ~f ~other =
|
||
|
|
match t1, t2 with
|
||
|
|
| Second x, Second y -> Second (f x y)
|
||
|
|
| First x, First y -> First (other x y)
|
||
|
|
| First x, _ | _, First x -> First x
|
||
|
|
;;
|
||
|
|
|
||
|
|
let bind t ~f =
|
||
|
|
match t with
|
||
|
|
| Second x -> f x
|
||
|
|
(* Reuse the value in order to avoid allocation, like [First.bind] above. *)
|
||
|
|
| First _ as y -> y
|
||
|
|
;;
|
||
|
|
end)
|
||
|
|
|
||
|
|
module Export = struct
|
||
|
|
type ('f, 's) _either = ('f, 's) t =
|
||
|
|
| First of 'f
|
||
|
|
| Second of 's
|
||
|
|
end
|