Zulip Chat Archive

Stream: new members

Topic: Synthesize typeclass instance


Rudy Peterson (Dec 10 2024 at 21:42):

Hello,

I am trying to define a Reader Monad and show it satisfies the monad laws:

class MonadLaws (M : Type -> Type) [Monad M] where

  pureL :  {α β : Type} (a : α) (f : α -> M β),
    pure a >>= f = f a

  pureR :  {α : Type} (m : M α),
    m >>= pure = m

  bindAssoc :  {α β γ} (m : M α) (f : α -> M β) (g : β -> M γ),
    m >>= f >>= g = m >>= (fun a => f a >>= g)

def ReaderMonad (M : Type -> Type) (ρ α : Type) : Type := ρ -> M α

instance ReaderMonad.Monad (M : Type -> Type) [Monad M] (ρ : Type) : Monad (ReaderMonad M ρ) where
  pure a := fun _ => pure a
  bind m f := fun r => m r >>= fun a => f a r

instance ReaderMonad.MonadLaws (M : Type -> Type) [Monad M] [MonadLaws M] (ρ : Type) : MonadLaws (ReaderMonad M ρ) where
  pureL a f := by sorry
  pureR m := by sorry
  bindAssoc m f g := by sorry

However in my declaration for ReaderMonad.MonadLaws I get an error for [Monad M]:

 66:52-66:59: error:
failed to synthesize
  _root_.Monad M
Additional diagnostic information may be available using the `set_option diagnostics true` command.

This error vanishes when I remove the dot from the name of ReaderMonad.Monad as:

instance ReaderMonadMonad (M : Type -> Type) [Monad M] (ρ : Type) : Monad (ReaderMonad M ρ) where
  pure a := fun _ => pure a
  bind m f := fun r => m r >>= fun a => f a r

Why is this happening? How can I get my code to work when there is still a dot in the name? I tried passing explicit typeclass arguments to MonadLaws but it did not help.

Thanks!

Matt Diamond (Dec 10 2024 at 23:40):

It looks like this is a namespace issue: since you're defining ReaderMonad.MonadLaws in the ReaderMonad namespace, it's confusing Monad with ReaderMonad.Monad. (Notice that the error also goes away if you remove the dot from the name of ReaderMonad.MonadLaws, bringing it out of the ReaderMonad namespace.)

It's a bit ugly, but one way to get around this is to change [Monad M] to [_root_.Monad M], explicitly specifying which Monad you're talking about.

Matt Diamond (Dec 10 2024 at 23:42):

A better way might be to rename ReaderMonad.Monad to ReaderMonad.instMonad, which is the naming convention that Lean follows (see e.g. docs#ReaderT.instMonad).

Matt Diamond (Dec 10 2024 at 23:52):

(maybe you're already aware but just wanted to note that Lean has docs#LawfulMonad and docs#LawfulMonad.mk')

Kevin Buzzard (Dec 11 2024 at 00:19):

Matt Diamond said:

A better way might be to rename ReaderMonad.Monad to ReaderMonad.instMonad, which is the naming convention that Lean follows (see e.g. docs#ReaderT.instMonad).

Or ReaderMonad.monad (the convention is capital letters for types, small for terms).

Rudy Peterson (Dec 31 2024 at 00:30):

Thanks!

I tried continuing and have the following:

instance ReaderMonad.instMonadLaws (M : Type -> Type) [iM : Monad M] [iML : MonadLaws M] (ρ : Type) : MonadLaws (ReaderMonad M ρ) where
  pureL a f := by
    funext r
    dsimp [bind, pure]
    rw [iML.pureL]

  pureR m := by
    funext r
    dsimp [bind, pure]
    rw [iML.pureR]

  bindAssoc m f g := by
    funext r
    dsimp [bind]
    rw [iML.bindAssoc]

def ReaderOption := ReaderMonad Option

instance ReaderOption.instMonad (ρ : Type) : Monad (ReaderOption ρ) := ReaderMonad.instMonad Option ρ

instance ReaderOption.instMonadLaws (ρ : Type) : MonadLaws (ReaderOption ρ) := ReaderMonad.instMonadLaws Option ρ

However, in my editor (doom emacs using lean4-mode) the entire declaration for ReaderMonad.instMonadLaws has yellow highlighting on the side, and lean rejects my definition for ReaderOption.instMonadLaws entirely with:

Messages below:
86:79:
failed to synthesize
  MonadLaws Option
Additional diagnostic information may be available using the `set_option diagnostics true` command.

How do I get it to find ReaderOption.instMonad?

Thanks!

Eric Wieser (Dec 31 2024 at 00:31):

Replacing def with abbrev might help

Rudy Peterson (Dec 31 2024 at 00:32):

Thanks for the suggestion! It still rejects it though:

abbrev ReaderOption := ReaderMonad Option

instance ReaderOption.instMonad (ρ : Type) : Monad (ReaderOption ρ) := ReaderMonad.instMonad Option ρ

instance ReaderOption.instMonadLaws (ρ : Type) : MonadLaws (ReaderOption ρ) := ReaderMonad.instMonadLaws Option ρ

Eric Wieser (Dec 31 2024 at 00:34):

Rudy Peterson said:

How do I get it to find ReaderOption.instMonad?

This is the wrong question, the thing you're looking for is MonadLaws Option but your suggested solution ReaderOption.instMonad is of type : Monad (ReaderOption ρ)

Eric Wieser (Dec 31 2024 at 00:35):

You need to prove that Option satisfies your MonadLaws

Rudy Peterson (Dec 31 2024 at 00:36):

Ah I see, somewhere above I had a:

def Option.instMonadLaws : MonadLaws Option where
  pureL a f := by rfl
  pureR m := by
    cases m
    case none   => rfl
    case some a => rfl
  bindAssoc m f g := by
    cases m
    case none   => rfl
    case some a => rfl

But when I change def to instance it is able to find it.


Last updated: May 02 2025 at 03:31 UTC