Zulip Chat Archive

Stream: metaprogramming / tactics

Topic: iterate until no change


Damiano Testa (Apr 15 2022 at 10:52):

Dear All,

I am a complete beginner with writing tactics, so I am very unsure whether what I ask is meaningful or not.

In trying to convert a procedure to compute degree of polynomials into a tactic, I would like to iterate a code-block until the initial state and the final one are the same. How can I do this? Below is a silly #mwe.

Thanks!

import tactic

example {a b : } : a + b = 0 :=
begin
-- this loops forever
  iterate { rw [add_comm, add_comm] },
end

Damiano Testa (Apr 15 2022 at 10:53):

(Fun fact, if you remove the import tactic, then iterate seems to stop quickly and possibly behave as I hoped it would.)

Damiano Testa (Apr 15 2022 at 10:55):

(The difference in behaviour between iterate with or without the import appears to be that with the import iterate seems to pause at each step and make sure that it has not already proven the goal.)

Damiano Testa (Apr 15 2022 at 11:14):

Actually, I am not sure about the difference: I think that one iterate has an explicit bound on the number of iterations, the other does not. Then there is a mix about rw that I did not know.

Floris van Doorn (Apr 15 2022 at 11:52):

I think tactic#repeat does what you want. It stops applying the tactic if it doesn't change the goal (or fails)

Damiano Testa (Apr 15 2022 at 12:05):

I am not sure what is going on, but this does not work (and in my use-case repeat also does not work):

meta def reprw : tactic unit :=
`[
  repeat { rw [add_comm] }
]

example {a b : } : a + b = b + a :=
begin
  reprw, -- ends as it started saying that there are unsolved goals
end

Damiano Testa (Apr 15 2022 at 12:06):

I meant to say: I am using this iterate not to solve the goal, but to massage it, so that after I can continue processing it.

Arthur Paulino (Apr 15 2022 at 12:07):

tactic#squeeze_simp has this behavior as well

Floris van Doorn (Apr 15 2022 at 12:09):

This works for me:

import tactic
meta def reprw : tactic unit :=
`[
  repeat { rw [add_comm] }
]

example {a b : } : a + b = b + a :=
begin
  reprw -- solves goal
end

Note: you need some kind of import, in order for add_comm to exist.

Damiano Testa (Apr 15 2022 at 12:11):

Ok, I'll continue investigating! I suspect that I minimised my example too much.

Damiano Testa (Apr 15 2022 at 12:12):

I find not getting an error for the add_comm very confusing!

Floris van Doorn (Apr 15 2022 at 12:12):

Note: a good way to debug issues with repeat is to just copy the tactic a couple of times and see where you get the first error:

example {a b : } : a + b = b + a :=
begin
  rw [add_comm], rw [add_comm], rw [add_comm]
end

Arthur Paulino (Apr 15 2022 at 12:12):

same_result is the function that you might want

Floris van Doorn (Apr 15 2022 at 12:13):

Damiano Testa said:

I find not getting an error for the add_comm very confusing!

This is a feature(?) of repeat: it will execute the tactic until the first time the tactic raises an error. The tactic raises an error the first time is applied, since it doesn't know what add_comm is.

Damiano Testa (Apr 15 2022 at 12:14):

Ok, thank you both for your help!

Floris van Doorn (Apr 15 2022 at 12:15):

You can also use docs#tactic.repeat1 (doesn't have an interactive version, I believe):

import tactic
meta def reprw : tactic unit :=
tactic.repeat1 `[rw [foobar]]

example {a b : } : a + b = b + a :=
begin
  reprw -- unknown identifier 'foobar'
end

Last updated: Dec 20 2023 at 11:08 UTC