Zulip Chat Archive
Stream: new members
Topic: Rewrite local `let` definitions
Gareth Ma (Oct 13 2023 at 01:11):
example : True := by
let c : ℕ → ℕ := fun x => x
have h {x : ℕ} : c (x + 1) = x + 1 := by
/- rw [c] -/
/- dsimp [c] -/
simp -- this works
What's the correct way to do this?
Gareth Ma (Oct 13 2023 at 01:12):
Something stupid like this also works:
example : True := by
let c : ℕ → ℕ := fun x => x
have h {x : ℕ} : c (x + 1) = x + 1 := by
rw [show c = fun x => x by rfl]
Gareth Ma (Oct 13 2023 at 01:41):
To make it closer to my scenario:
example : True := by
let f : ℕ → ℕ := fun x => x
let g : (ℕ → ℕ) → (ℕ → ℕ) := fun y => (fun x => Nat.floor ((cos (sin ↑x)) ^ 2 / 5)) -- complicated things
have h : g (fun x => 2 * f x) = g (fun x => x * 2) + g (fun _ => 0) := by
dsimp only [f] -- ??
I don't want to expand g's definition because it's quite complicated. I want to expand f first so that f x gets replaced with x, but I can't figure out a way to do that.
Timo Carlin-Burns (Oct 13 2023 at 01:58):
It seems a little annoying to rewrite using the definitions of lets compared to top-level declarations... The reason rw [f] would work if you had def f := ... is because of a feature called "equational lemmas", where a lemma theorem f._eq_ (n : ℕ) : f n = n is generated alongside your definition which rw and simp automatically look for when you try rw [f].
Timo Carlin-Burns (Oct 13 2023 at 01:59):
I wonder if there's a tactic which generates a hypothesis that a let equals its definition. So here hf : \all n, f n = n
Timo Carlin-Burns (Oct 13 2023 at 02:02):
if you want f to be expanded everywhere, I think you could try letI f instead of let f. The I stands for "inline" and it automatically substitutes the definition of f inline whenever it is referenced
Timo Carlin-Burns (Oct 13 2023 at 02:03):
ah! maybe unfold_let would work?
Gareth Ma (Oct 13 2023 at 02:04):
Oh wow, yes unfold_let works perfectly, thanks.
Alex J. Best (Oct 13 2023 at 02:05):
You can also use set a := 1 with h to get a named hypothesis which is helpful
Gareth Ma (Oct 13 2023 at 02:06):
Ah, that's how to do the "equational lemma" thing then.
Timo Carlin-Burns (Oct 13 2023 at 02:11):
I just tested letI and it didn't seem to make a difference so I guess it doesn't do what I thought :shrug:
Chris Wong (Oct 13 2023 at 02:22):
I thought letI was about instances?
Chris Wong (Oct 13 2023 at 02:23):
Ah, they changed it from Lean 3 to 4 :sweat_smile:
Gareth Ma (Oct 13 2023 at 02:29):
Another related question, is funext within conv removed in Lean 4? Or not ported?
Gareth Ma (Oct 13 2023 at 02:31):
Is there any way to rewrite this in Lean 4?
example : (fun x => x + 0) = (fun x => x) := by
-- rw [add_zero] -- fails
conv =>
lhs
funext -- fails
rw [add_zero]
rfl
Timo Carlin-Burns (Oct 13 2023 at 02:32):
looks like ext instead of funext works?
Gareth Ma (Oct 13 2023 at 02:35):
Oh thanks a lot
Gareth Ma (Oct 13 2023 at 02:35):
That will save me a lot of time :sweat_smile:
Timo Carlin-Burns (Oct 13 2023 at 02:36):
simp_rw [add_zero] also works if the challenge is rewriting under binders
Gareth Ma (Oct 13 2023 at 02:37):
Oh so simp_rw goes inside binders as well
Gareth Ma (Oct 13 2023 at 02:37):
Nice. I finally proved my result after like a few hours..
Eric Wieser (Oct 13 2023 at 12:03):
To turn off this "expand all lets" behavior, you can use dsimp (config := { zeta := false }) only [f] which will not unfold g
Eric Wieser (Oct 13 2023 at 12:03):
There is a thread somewhere petitioning to make this the default
Eric Rodriguez (Oct 13 2023 at 12:09):
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/simp.20unfolding.20let.20bindings
Eric Rodriguez (Oct 13 2023 at 12:09):
Should I just open a core lean4 issue?
Eric Rodriguez (Oct 13 2023 at 13:22):
Last updated: May 02 2025 at 03:31 UTC