Zulip Chat Archive

Stream: new members

Topic: Fields missing error while defining Monad


Ichinoe (Apr 18 2024 at 04:01):

I'm learning Monad Operations of Functional Programming in Lean, and writing codes like this:

structure WithLog (logged : Type) (α : Type) where
  log : List logged
  val : α

instance : Monad <| WithLog logged where
  pure val := ⟨[], val
  bind item next :=
    let nextItem := next item.val
    item.log ++ nextItem.log, nextItem.val

and it says fields missing: 'map', 'mapConst', 'seq', 'seqLeft'.

But if I write as what the textbook does, there would be no error:

structure WithLog (logged : Type) (α : Type) where
  log : List logged
  val : α

instance : Monad <| WithLog logged where
  pure val := ⟨[], val
  bind item next :=
    let {log := nextOut, val := nextRes} := next item.val
    item.log ++ nextOut, nextRes

Why is this happening? I found a similar post but it doesn't seems to be of help to this problem.

Yuyang Zhao (Apr 18 2024 at 04:13):

#mwe

def Option' := Option

instance : Monad Option' where
  pure := Option.some
  bind a f :=
    let b := Option.bind a f
    b

Yuyang Zhao (Apr 18 2024 at 04:29):

It looks like let makes Lean fail to assign default values to fields.

Utensil Song (Apr 18 2024 at 04:55):

It's weird that the following works despite that it didn't use let destructuring:

structure WithLog (logged : Type) (α : Type) where
  log : List logged
  val : α

set_option trace.Meta.synthInstance true
set_option synthInstance.checkSynthOrder true

instance : Pure <| WithLog logged where
  pure val := ⟨[], val

instance : Bind <| WithLog logged where
  bind item next :=
    let nextItem := next item.val
    item.log ++ nextItem.log, nextItem.val

/-
failed to synthesize
  Monad (WithLog logged)
-/
variable (logged : Type) in
#synth Monad <| WithLog logged

-- empty body works
instance : Monad <| WithLog logged where

-- success
variable (logged : Type) in
#synth Monad <| WithLog logged

Utensil Song (Apr 18 2024 at 05:04):

or the shorter working version for @Yuyang Zhao 's (intentially) non-working #mwe:

def Option' := Option

instance : Pure Option' where
  pure := Option.some

instance : Bind Option' where
  bind a f :=
    let b := Option.bind a f
    b

instance : Monad Option' where

Yuyang Zhao (Apr 18 2024 at 05:07):

I think Bind is already defined in this example when defining Monad (and then assigning default values to its fields). It will not be expanded to a let expression.

Utensil Song (Apr 18 2024 at 07:20):

def Option' := Option

instance : Monad Option' where
  pure := Option.some
  bind := fun a f =>
    let rec b := Option.bind a f
    b

let rec works, for both #mwe and the original example.

Utensil Song (Apr 20 2024 at 14:13):

But why doesn't this further minimized #mwe fail with let?

class A (t : Type) where
  a : t  t

class B (t : Type) extends A t where
  b : t  t

class C (t : Type) extends B t where
  b := fun x  A.a x

structure D (t : Type) where
  d : t  t

instance : C <| D t0 where
  a := fun x 
    let xd := x.d
    xd

Utensil Song (May 10 2024 at 13:12):

I want to note that this case is still a mystery to me. let, let rec and let fun are implemented in very different ways despite the syntax similarity, so even though I suspect the issue is in the let implementation, I have no clue.

Mario Carneiro (May 10 2024 at 13:24):

let fun doesn't exist

Mario Carneiro (May 10 2024 at 13:24):

oh you mean let_fun

Mario Carneiro (May 10 2024 at 13:24):

which is basically the same as have

Mario Carneiro (May 10 2024 at 13:26):

What's the issue in the above code? I get no errors, and it sounds like this is expected

Utensil Song (May 10 2024 at 13:38):

The issue is with the #mwe in the 2nd message.

As it seems that let makes Lean fail to assign default values to fields.

Comparing that with this:

def Option' := Option

instance : Monad Option' where
  pure := Option.some
  bind := Option.bind

which would work without the error about missing fields.

Arthur Adjedj (May 10 2024 at 14:44):

This is lean4#3146, fixed in lean4#3152.

Utensil Song (May 10 2024 at 15:00):

Thanks for the fix!

The fix looks subtle to me, as the original code looks innocent and aligns with other match branches. Is it possible that the issues applies to not only let and the cause is rooted somewhere else where this lingering of metavariables could be treated altogether for all applied constructs?

Arthur Adjedj (May 10 2024 at 15:26):

I'm not sure I understand what you're proposing. What causes the metavariables to linger in the first place is that reduce, which serves (among other things) to instantiate metavariables doesn't do so in the subexpressions bound in lets. Because the system relies on checking whether there are still some unsolved metavars to know whether default fields have been effectively elaborated, this looks like the most sensible solution to me.

Arthur Adjedj (May 10 2024 at 15:32):

Though now that I think about this again, it might be possible to find such lingering mvars in the type of variables in the local context, and not just in their values. I believe I couldn't manage to trigger an error in such situations when testing back when I made my PR, but I might as well take another look.

Utensil Song (May 10 2024 at 15:33):

Yes, the fix is sensible for fixing the let issue. My concern was merely that the other match branches are only doing a mk...reduce combo, is it that let is special, or other branches might need the same treatment for the metavariables.

Arthur Adjedj (May 10 2024 at 15:40):

let is special in that it is the only branch which introduces a new term (and its type) in the local context, the other special cases would be lambda and forall, which introduce new types in the local context

Utensil Song (May 10 2024 at 15:59):

(deleted)

Utensil Song (May 10 2024 at 15:59):

I see, thanks for the explanation.


Last updated: May 02 2025 at 03:31 UTC