Global Set Automatic Coercions Import.
Set Implicit Arguments.
Record Monad: Type :=
{ mon:> Set -> Set
; bind: forall a b, mon a -> (a -> mon b) -> mon b
; ret: forall (a: Set), a -> mon a
(* Laws: *)
; mon_lunit: forall (a b: Set) (x: a) (f: a -> mon b), bind (ret x) f = f x
(* (return x >>= f) = (f x) *)
; mon_runit: forall (a: Set) (f: mon a), bind f (@ret a) = f
(* (f >>= return) = f *)
; mon_assoc: forall a b c (n: mon a) (f: a -> mon b) (g: b -> mon c),
bind (bind n f) g =
bind n (fun x => bind (f x) g)
(* ((n >>= f) >>= g) = n >>= (\x -> f x >>= g) *)
}.
(* Todo: I vaguely recall someone mentioning that there was a way to use notation and/or implicit arguments inside a record definition. That would make the above a lot cleaner. *)
Arguments bind [m a b].
Arguments ret {m a}.
Notation "x >>= y" := (bind x y) (at level 55).
Notation "x >> y" := (bind x (fun _ => y)) (at level 30, right associativity).
Notation "x <- y ; z" := (bind y (fun x : _ => z)) (at level 30, right associativity).
Record Functor: Type :=
{ func: Set -> Set
; func_map: forall (a b: Set) (f: a -> b), func a -> func b
(* Laws: *)
; func_id: forall (X: Set), func_map (fun (x: X) => x) = (fun (x: func X) => x)
(* (id .) = id *)
; func_assoc: forall (a b c: Set) (x: func a) (f: b -> c) (g: a -> b),
func_map (f ∘ g) x = func_map f (func_map g x)
(* (f . g) . x = f . (g . x) *)
}.
Arguments func_map [f a b].
Definition extMonad (M: Monad): Prop := forall (A B: Set) (f g: A -> M B), ext_eq f g -> forall x, bind x f = bind x g.

(* Specifications: *)
Lemma bind_eqq (M: Monad) (e: extMonad M) (A B: Set) (m n: M A) (f g: A -> M B):
m = n -> ext_eq f g -> (m >>= f) = (n >>= g).