Set Implicit Arguments.
Require list_utils.
Record Monoid: Type :=
{ monoid_type:> Set
; monoid_zero: monoid_type
; monoid_mult: monoid_type -> monoid_type -> monoid_type
; monoid_lunit: forall x, monoid_mult monoid_zero x = x
; monoid_runit: forall x, monoid_mult x monoid_zero = x
; monoid_assoc: forall x y z, monoid_mult (monoid_mult x y) z = monoid_mult x (monoid_mult y z)
}.
Record monoidHomo (m n: Monoid) (f: m -> n): Prop :=
{ monoidHomo_zero: f (monoid_zero m) = (monoid_zero n)
; monoidHomo_mult: forall x y, f (monoid_mult m x y) = monoid_mult n (f x) (f y)
}.
Definition lift (A: Set) (a: monad A): M A := a >>= (ret ∘ pair (monoid_zero monoid)).
End NewMonad.
Definition T: MonadTrans := Build_MonadTrans M lift.
End MonoidMonadTrans.
End MonoidMonadTrans.
Definition NatAddMonoid: Monoid.
Proof with auto with arith.
apply (Build_Monoid 0 plus)...
Defined.
Definition SimplyProfiled: Monad := MonoidMonadTrans.M NatAddMonoid IdMonad.ext.
Definition cost {X: Set}: prod nat X -> nat := @fst _ _.
Definition result X: SimplyProfiled X -> X := @snd _ _.

Lemma bind_cost (T U: Set) (a: SimplyProfiled T) (b: T -> SimplyProfiled U):
cost (bind a b) = cost a + cost (b (result a)).