Zulip Chat Archive

Stream: general

Topic: Using `simp` inductively breaks `deriving_by` proof state


Ayhon (May 14 2025 at 14:46):

When the simp tactic performs an inductive step in a proof, the proof state obtained in the deriving_by section contains duplicated definitions that generally prevent you from closing the goal.

Her's a MWE.

def foo(ls: List Bool)(i: Nat): List Bool :=
  if i + 1 < ls.length then foo ls (i + 1) else ls
termination_by ls.length - i

def length_foo(ls: List Bool)(i: Nat)
: (foo ls i).length = ls.length
:= by
  unfold foo
  split
  · simp [*, length_foo]
  · simp
termination_by ls.length - i
decreasing_by
  try omega
  sorry

The position with the sorry is where one can see the mangled proof state.

Notification Bot (May 14 2025 at 14:47):

This topic was moved here from #general > Weird proof state in deriving_by by Ayhon.

Robin Arnez (May 15 2025 at 06:44):

Hmm looking at this using by? it seems like there are some non-beta reduced proofs: (fun ls i => length_foo ls i) ls (i + 1).

Robin Arnez (May 15 2025 at 06:44):

So you could use a beta-reduction combinator:

import Lean.Elab

def foo (ls : List Bool) (i : Nat) : List Bool :=
  if i + 1 < ls.length then foo ls (i + 1) else ls

open Lean Elab Term Meta in
elab "beta_reduce" x:term : term <= expected => do
  let expected  instantiateMVars expected
  let expected  Core.betaReduce expected
  let term  elabTermAndSynthesize x expected
  let term  instantiateMVars term
  Core.betaReduce term

theorem length_foo (ls : List Bool) (i : Nat) : (foo ls i).length = ls.length := beta_reduce by
  unfold foo
  split
  · simp [*, length_foo]
  · simp

Last updated: Dec 20 2025 at 21:32 UTC