Zulip Chat Archive

Stream: lean4

Topic: stray metavariable in goal, looks like a bug?


Kim Morrison (Nov 07 2024 at 23:03):

def SatisfiesM {m : Type u  Type v} [Functor m] (p : α  Prop) (x : m α) : Prop :=
   x' : m {a // p a}, Subtype.val <$> x' = x

/-- A monad is "satisfying" if we can lift `SatisfiesM` to a monadic value in `Subtype`. -/
class Satisfying (m : Type u  Type v) [Monad m] where
  lift (p : α  Prop) (x : m α) (h : SatisfiesM (m := m) p x) :
    { y : m {a // p a} // Subtype.val <$> y = x }

instance : Satisfying Option where
  lift (p) x? h :=
  { val := x?.attach.map fun x, w => x, by
      obtain a?, rfl := h
      match a? with
      | none => simp at w
      | some a =>
        simp at w
        simp [ w]
        exact a.2
    property := by
      cases x? with
      | none => simp
      | some x => simp } -- Why is there a metavariable in the goal???

At the final simp I see a goal of the form ⊢ (?m.651 (some x) h ⟨x, ⋯⟩).val = x, i.e. with a stray metavariable. This is a bug, right?

I can work around this by extracting out the value of val into a helper function.

Daniel Weber (Nov 08 2024 at 04:55):

Even just extracting the proof in val to another function works, but using by exact doesn't:

def SatisfiesM {m : Type u  Type v} [Functor m] (p : α  Prop) (x : m α) : Prop :=
   x' : m {a // p a}, Subtype.val <$> x' = x

/-- A monad is "satisfying" if we can lift `SatisfiesM` to a monadic value in `Subtype`. -/
class Satisfying (m : Type u  Type v) [Monad m] where
  lift (p : α  Prop) (x : m α) (h : SatisfiesM (m := m) p x) :
    { y : m {a // p a} // Subtype.val <$> y = x }

theorem extracted_1.{u_1} {α : Type u_1} (p : α  Prop) (x? : Option α) (h : SatisfiesM p x?) (x : α) (w : x  x?) :
    p x := by
  obtain a?, rfl := h
  match a? with
  | none => simp at w
  | some a =>
    simp at w
    simp [ w]
    exact a.2

instance : Satisfying Option where
  lift (p) x? h :=
  { val := x?.attach.map fun x, w => x, extracted_1 p x? h x w
    property := by
      cases x? with
      | none => simp
      | some x => simp } -- Works

instance : Satisfying Option where
  lift (p) x? h :=
  { val := x?.attach.map fun x, w => x, by exact extracted_1 p x? h x w
    property := by
      cases x? with
      | none => simp
      | some x => simp } -- Why is there a metavariable in the goal???

Daniel Weber (Nov 08 2024 at 04:57):

I think it's because by delays elaboration, so val isn't fully determined when you prove property

Daniel Weber (Nov 08 2024 at 05:18):

Minimized:

def lift (p : α  Prop) (x? : Option α) : { y : Option {a // p a} // Subtype.val <$> y = x? } :=
  { val := x?.attach.map fun x, w => x, sorry
    property := by
      cases x? with
      | none => simp
      | some x => simp } -- OK

def lift2 (p : α  Prop) (x? : Option α) : { y : Option {a // p a} // Subtype.val <$> y = x? } :=
  { val := x?.attach.map fun x, w => x, by sorry
    property := by
      cases x? with
      | none => simp
      | some x => simp } -- Why is there a metavariable in the goal???

Kim Morrison (Nov 08 2024 at 10:59):

(Just did some poking around, this has always been a problem, it's not a regression.)

Kyle Miller (Nov 08 2024 at 15:36):

It seems like it could have to do with the implicit match in that fun definition postponing things as well. Using projection notation is a way to fix it:

def lift3 (p : α  Prop) (x? : Option α) : { y : Option {a // p a} // Subtype.val <$> y = x? } :=
  { val := x?.attach.map fun x => x.1, by sorry
    property := by
      cases x? with
      | none => simp
      | some x => simp }

Kyle Miller (Nov 08 2024 at 15:37):

instance : Satisfying Option where
  lift (p) x? h :=
  { val := x?.attach.map fun x => x.1, by
      have w := x.2
      obtain a?, rfl := h
      match a? with
      | none => simp at w
      | some a =>
        simp at w
        simp [ w]
        exact a.2
    property := by
      cases x? with
      | none => simp
      | some x => simp }

Last updated: May 02 2025 at 03:31 UTC