Zulip Chat Archive
Stream: lean4
Topic: Reasoning about monad transformer
Yicheng Qian (Sep 03 2022 at 06:51):
How can I prove that "If m is a valid monad, then (EitherT m e) is a valid monad"?
class QMonad (inst : Monad m) where
pure_l : ∀ (x : α) (f : α → m β), pure x >>= f = f x
pure_r : ∀ (x : m α), x >>= pure = x
bind_assoc : ∀ (ma : m α) (f : α → m β) (g : β → m γ),
ma >>= (fun x => f x >>= g) = (ma >>= f) >>= g
def EitherT (m : Type _ → Type _) e a := m (a ⊕ e)
instance [H : Monad m] : Monad (EitherT m e) where
-- pure : a -> m (a ⊕ e)
pure := H.pure ∘ Sum.inl
bind ma amb := H.bind ma (fun a =>
match a with
| Sum.inl a => amb a
| Sum.inr e => H.pure (Sum.inr e))
instance [H : Monad m] [Q : QMonad H] :
QMonad (instMonadEitherT (e:=e) (H:=H)) where
pure_l := sorry
pure_r := sorry
bind_assoc := sorry
Tomas Skrivan (Sep 03 2022 at 07:05):
There is LawfulMonad
class https://github.com/leanprover/lean4/blob/37252e5fa7eff2ce938b7b63f72c0f40cab7e878/src/Init/Control/Lawful.lean#L46 that has these rules.
And for example here is proof of lawfulness of StateT
https://github.com/leanprover/lean4/blob/37252e5fa7eff2ce938b7b63f72c0f40cab7e878/src/Init/Control/Lawful.lean#L298
Yicheng Qian (Sep 03 2022 at 07:07):
Thanks. I'll try to figure it out.
Yicheng Qian (Sep 03 2022 at 07:16):
There is ExceptT
which is essentially EitherT
https://github.com/leanprover/lean4/blob/37252e5fa7eff2ce938b7b63f72c0f40cab7e878/src/Init/Control/Lawful.lean#L101
And the proof of its lawfulness
https://github.com/leanprover/lean4/blob/37252e5fa7eff2ce938b7b63f72c0f40cab7e878/src/Init/Control/Lawful.lean#L163
Jan-Mirko Otter (Sep 03 2022 at 08:02):
I just tried to prove the first one, pure_l
, by just "plugging in the definitions" and using the pure_l
rule of the original monad.
I came up with the following behaviour which is kind of surprising for me:
-- same as above, stripped for clarity
instance [H : Monad m] [Q : QMonad H] :
QMonad (instMonadEitherT (e:=e) (H:=H)) where
pure_l := by
intro U V x f
conv =>
lhs
-- Why is this block necessary?
change H.bind (pure x : EitherT m e U) (fun (a : U ⊕ e) =>
match a with
| Sum.inl a => f a
| Sum.inr e => H.pure (Sum.inr e))
change (H.pure (Sum.inl x) : EitherT m e U) >>= (fun (a : U ⊕ e) =>
match a with
| Sum.inl a => f a
| Sum.inr e => H.pure (Sum.inr e))
rw [QMonad.pure_l]
pure_r := sorry
bind_assoc := sorry
If instances and notations are involved, I find it very difficult to use unfold
or whnf
, so I basically have to plug in the defintions manually using change
. However, while the proof above works, I do not understand why the first change
block is necessary. If I remove it, the argument of the remaining change
does not typecheck any more.
Any ideas?
Yicheng Qian (Sep 03 2022 at 08:27):
I also find it difficult to use rw
, apply
, unfold
, etc. when instances and notations are involved.
I'm not very sure why the first block is necessary, but the three properties can be proved as follows:
instance [H : Monad m] [Q : QMonad H] :
QMonad (instMonadEitherT (e:=e) (H:=H)) where
pure_l := fun x f => Q.pure_l _ _
pure_r := fun x =>
by simp [bind]
have : H.bind x pure = x := Q.pure_r _
rw [←this]
apply congr
. rw [Q.pure_r]
. apply funext; intro x
cases x <;> rfl
bind_assoc := fun ma f g =>
by simp [bind]
rw [←Q.bind_assoc]
apply bind_congr; intros a
cases a with
| inl => rfl
| inr => rw [Q.pure_l]
Yicheng Qian (Sep 03 2022 at 08:31):
I read the proof of the lawfulness of ExceptT
at https://github.com/leanprover/lean4/blob/37252e5fa7eff2ce938b7b63f72c0f40cab7e878/src/Init/Control/Lawful.lean#L163, and found that in the proof there is ExceptT.mk
and ExceptT.run
, which seems to be useful. There also seems to be some tricks which I do not fully understand.
Tomas Skrivan (Sep 03 2022 at 08:46):
When notation gets confusing, try set_option pp.notation false
. It can help to clear things up.
Also stylistic nitpick, the class QMonad
should be declared as:
class QMonad (m : Type _ → Type _) [Monad m] where ...
and the instance:
instance {m} [Monad m] [QMonad m] : QMonad (EitherT m e) where
Only in rare cases it makes sense to ask for a class as an explicit argument, like (inst : Monad m)
.
Last updated: Dec 20 2023 at 11:08 UTC