Zulip Chat Archive

Stream: general

Topic: Rewrite outside first


Michael Swan (Jan 15 2024 at 00:10):

If I have a goal of the form:

f x = f (f x)

and I would like to rewrite that outer f on the right-hand side, how can that be done? It seems that whenever I do rw [f] it will only ever perform this operation on either the left-hand side or the inner most function application on the right-hand side but never the outer invocation. nth_rewrite i [f] also doesn't allow me to rewrite that specific use of f for any index I provide.

Adam Topaz (Jan 15 2024 at 00:18):

You could use conv mode (possibly with the fancy new widget) to select which f to rewrite explicitly

Michael Swan (Jan 15 2024 at 00:20):

Okay, I’ll experiment with that

Matt Diamond (Jan 15 2024 at 00:22):

I'm surprised you can't get nth_rewrite to do the job... this seems to work for me:

import Mathlib.Tactic.NthRewrite

example {α : Type} (f g : α  α) (hf : f = g) (x : α): f x = f (f x) := by
  nth_rewrite 2 [hf]
  -- goal is now f x = g (f x)

Matt Diamond (Jan 15 2024 at 00:26):

maybe there's something about the particulars of your case that are interfering... in that case I suppose conv will do the trick, as Adam said

Adam Topaz (Jan 15 2024 at 00:28):

If you could give a #mwe that would be great, if you still need help

Michael Swan (Jan 15 2024 at 00:47):

Yeah nth_rewrite doesn't work for my problem, here is a minimal example:

import Mathlib

inductive code : Type
| seq (c1 c2: code)
| skip
open code

def right_append_seq (c1 c2: code) : code :=
  match c1 with
  | seq c1' c2' => seq c1' (right_append_seq c2' c2)
  | _           => seq c1 c2

def right_assoc_seq : code -> code
| seq (seq c1 c2) c3 => right_append_seq (right_assoc_seq c1) (right_append_seq (right_assoc_seq c2) (right_assoc_seq c3))
| seq c1 c2 => right_append_seq (right_assoc_seq c1) (right_assoc_seq c2)
| c => c

theorem right_assoc_seq_idempotent :  c, right_assoc_seq c = right_assoc_seq (right_assoc_seq c) := by
  intros c
  induction c with
  | seq c1 c2 h1 h2 => nth_rewrite 2 [right_assoc_seq] -- Here is where things fail.

Michael Swan (Jan 15 2024 at 00:49):

I am trying to expand that outer-most right_assoc_seq but that does not appear to be an option.

Kim Morrison (Jan 15 2024 at 00:54):

What are you expecting it to expand to? Lean can't see yet which of the branches of the definition of right_assoc_seq applies here.

Kim Morrison (Jan 15 2024 at 00:55):

(Note that the third branch c => c only applies for c = skip.)

Michael Swan (Jan 15 2024 at 00:57):

I expect it to expand into separate goals for each possibility of the inner (right_assoc_seq c) expression, which I guess perhaps that means I should do induction/cases on that expression?

Michael Swan (Jan 15 2024 at 00:59):

I guess I should just expand the inner and then the outer and that might be the only way to do anything with this.

Kyle Miller (Jan 15 2024 at 01:09):

This seems to unfold the outer one and split into three cases:

theorem right_assoc_seq_idempotent :  c, right_assoc_seq c = right_assoc_seq (right_assoc_seq c) := by
  intros c
  induction c with
  | skip => sorry
  | seq c1 c2 h1 h2 =>
    conv_rhs => unfold right_assoc_seq
    split
    -- three goals

Michael Swan (Jan 15 2024 at 01:10):

Yeah, I'm going to need to rethink what I'm doing. I think there is a saner way to solve this than what I was attempting to do. Starting this proof with intros c; induction (right_assoc_seq c) seems to get me way farther than intros c; induction c


Last updated: May 02 2025 at 03:31 UTC