Zulip Chat Archive

Stream: lean4

Topic: tactic 'generalize' failed


Marcus Rossel (Feb 20 2022 at 20:25):

I can't for the life of me figure out how to perform induction on a list, when the goal contains a proof term that involves that list.
Here's an MWE:

def List.attach [BEq α] (l : List α) : List {x // l.contains x} := sorry

inductive B deriving BEq
structure A where bs : Nat  List B

def f {a : A} {b : B} {n} (hc : (a.bs n).contains b) : Nat := sorry

example (a : A) (n : Nat) : (a.bs n).attach.map (f ·.property) = [] := by
  induction (a.bs n)

The compiler says:

tactic 'generalize' failed, result is not type correct
   (x : List B), List.map (fun a_1 => f (_ : List.contains x a_1.val = true)) (List.attach x) = []
a : A
n : Nat
 List.map (fun a_1 => f (_ : List.contains (A.bs a n) a_1.val = true)) (List.attach (A.bs a n)) = []

I can make that error go away temporarily, by doing:

example (a : A) (n : Nat) : (a.bs n).attach.map (f ·.property) = [] := by
  cases a
  case mk bs =>
    induction (bs n) <;> simp only [A.bs] at *

But then again, the simp only [A.bs] at * does not rewrite the proof term, so I'm still stuck:

case nil
n : Nat
bs : Nat  List B
 List.map (fun a => f (_ : List.contains (A.bs { bs := bs } n) a.val = true)) (List.attach (bs n)) = []

case cons
n : Nat
bs : Nat  List B
head : B
tail : List B
tail_ih : List.map (fun a => f (_ : List.contains (A.bs { bs := bs } n) a.val = true)) (List.attach (bs n)) = []
 List.map (fun a => f (_ : List.contains (A.bs { bs := bs } n) a.val = true)) (List.attach (bs n)) = []

Chris B (Feb 20 2022 at 21:21):

Will this work for what you're doing?

example (l : List B) :  (a : A) (n : Nat), l = (a.bs n) -> (a.bs n).attach.map (f ·.property) = [] := by
  induction l with
  | nil =>
    trace_state
    sorry
  | cons h t ih =>
    trace_state
    sorry

Marcus Rossel (Feb 21 2022 at 08:46):

Chris B said:

Will this work for what you're doing?

example (l : List B) :  (a : A) (n : Nat), l = (a.bs n) -> (a.bs n).attach.map (f ·.property) = [] := by
  induction l with
  | nil =>
    trace_state
    sorry
  | cons h t ih =>
    trace_state
    sorry

Hmm, I think not. I still get stuck at not being able to rewrite the proof term.
Perhaps I don't understand what you're hinting at with this approach.
E.g. the nil case in your example should be provable, but I can't prove it because I can't rewrite the l = a.bs n (in the nil case: [] = a.bs n) in the .attach term.

Chris B (Feb 21 2022 at 15:55):

Marcus Rossel said:

Perhaps I don't understand what you're hinting at with this approach.

It's just generalizing it by hand, moving things rightward into the motive and then adding an equality hypothesis. The hang-up here seems to be the dependent argument to f. If you can get away with making it def f {b : B} {l : List B} (hc : l.contains b) : Nat := or def f {b : B} {l : List B} (hc : l.contains b) (h' : ∃ (a: A) (n : Nat), l = a.bs n) : Nat := sorry things should go more smoothly.

Chris B (Feb 21 2022 at 15:57):

As it is, you can get a little closer by filling in the implicits, but the last type-level rewrite seems a bridge too far. The rewrite gives the 'motive not type correct' error.

example (l : List B) :  (a : A) (n : Nat) (h : a.bs n = l), l.attach.map (fun z => @f a z.val n (h  z.property)) = [] := by
  induction l with
  | nil =>
    intro a n h
    --rw [h]
    sorry
  | cons h t ih =>
    trace_state
    sorry

Last updated: Dec 20 2023 at 11:08 UTC