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):

lean4#2682


Last updated: Dec 20 2023 at 11:08 UTC