Zulip Chat Archive
Stream: Is there code for X?
Topic: apply function n times
Bernd Losert (Feb 20 2022 at 00:26):
Is there a tactic that can take an n : ℕ, f : α → β, and x : α and produce f (f ... (f x)...), where f appears n times.
Bernd Losert (Feb 20 2022 at 00:26):
(deleted)
Kevin Buzzard (Feb 20 2022 at 00:29):
There's docs#nat.iterate (assuming you mean f : α → α
) -- why do you need a tactic?
Bernd Losert (Feb 20 2022 at 00:30):
I can't use iterate because f is polymorphic and each application of f produce different types.
Bernd Losert (Feb 20 2022 at 00:31):
For example, suppose f
is functor.map
.
Kevin Buzzard (Feb 20 2022 at 00:39):
If the codomain and domain of f
are different then I can make no sense of your question. What do the ...
mean in your first post?
Yaël Dillies (Feb 20 2022 at 00:41):
How do you know that the n + 1
-th application will be polymorphic enough to accept the n
-th output?
Bernd Losert (Feb 20 2022 at 00:50):
A more concrete example:
constant xs : list (list (list nat))
constant f : nat → string
def ex : list (list (list string)) := list.map (list.map (list.map f)) xs
Bernd Losert (Feb 20 2022 at 00:51):
I want a tactic where I can write something like (iterate 3 list.map f) xs
Mario Carneiro (Feb 20 2022 at 00:53):
iterate 3 { apply list.map f }, exact xs
?
Bernd Losert (Feb 20 2022 at 00:57):
What isiterate
in that line of code?
Yaël Dillies (Feb 20 2022 at 00:57):
docs#tactic.interactive.iterate
Bernd Losert (Feb 20 2022 at 01:00):
Ah, OK. I tried
def ex : list (list (list string)) := begin
iterate 3 { apply list.map f }, exact xs
end
but it complains about apply
.
Mario Carneiro (Feb 20 2022 at 01:19):
actually you aren't applying directly to the goal in that example so you have to modify it a bit
def ex : list (list (list string)) := begin
have := xs, revert this,
iterate 3 { apply list.map }, exact f
end
Bernd Losert (Feb 20 2022 at 10:51):
Nice. I tried the following, but it does not work:
noncomputable def ex (n : ℕ) : nat.iterate list n string := begin
have := xs, revert this,
iterate n { apply list.map }, exact f
end
Reid Barton (Feb 20 2022 at 10:53):
what's the type of xs
here?
Bernd Losert (Feb 20 2022 at 10:53):
Oops. I forgot to change that one.
Reid Barton (Feb 20 2022 at 10:53):
the way you're mixing the levels doesn't make sense here, you should just be able to use induction on n though
Bernd Losert (Feb 20 2022 at 10:53):
Let me try again.
Reid Barton (Feb 20 2022 at 10:55):
I feel like the answers involving the iterate
tactic were possibly misleading, but then, it's also quite unclear what you want to do or why
Bernd Losert (Feb 20 2022 at 10:56):
Here you go:
def ex (n : ℕ) (f : nat → string) (xs : nat.iterate list n nat) : nat.iterate list n string := begin
have := xs, revert this,
iterate n { apply list.map }, exact f
end
Reid Barton (Feb 20 2022 at 10:58):
I guess you should move all arguments (except optionally f
) to the right of the colon and use recursion
Bernd Losert (Feb 20 2022 at 11:00):
That's a good idea actually. But why does it not work with the iterate
tactic. Does that tactic only work with hard-code n
?
Reid Barton (Feb 20 2022 at 11:00):
Right, it just doesn't make sense
Reid Barton (Feb 20 2022 at 11:00):
iterate
needs to know how many times to run the body, that number cannot be an internal variable
Bernd Losert (Feb 20 2022 at 11:01):
Bummer... Oh well.
Reid Barton (Feb 20 2022 at 11:01):
There is a phase distinction here
Bernd Losert (Feb 20 2022 at 11:03):
What do you mean by "phase"?
Reid Barton (Feb 20 2022 at 11:04):
e.g. compile-time vs run-time
Reid Barton (Feb 20 2022 at 11:05):
The tactic runs before the function itself (notionally) runs. So n
doesn't refer to anything when the tactic executes, it's literally just the letter "n".
Reid Barton (Feb 20 2022 at 11:07):
It's like C macros, you cannot have a program expand a macro n
times where n
is a number the program read from stdin, because the macro expansion already had to be finished long ago
Reid Barton (Feb 20 2022 at 11:09):
In Lean it would make even less sense because the tactic block could be constructing a proof, and proofs don't even run at all.
Bernd Losert (Feb 20 2022 at 11:10):
Yes, that makes sense. For some reason, I thought I could get away with doing this sort of thing in Lean. I have come across this limitation with other macro systems. I guess this is a fundametal issue with macros in general.
Bernd Losert (Feb 20 2022 at 11:17):
So, I trying this, but I'm getting errors that I don't know how to fix:
def ex (f : nat → string) : ∀ n, (list^[n] nat) → (list^[n] string)
| (0) (n) := f n
| (n + 1) ([]) := []
| (n + 1) (list.cons m ms) := sorry,
Reid Barton (Feb 20 2022 at 11:23):
Hmm, I think nat.iterate
is defined inconveniently for this purpose
Reid Barton (Feb 20 2022 at 11:23):
You would prefer to have list^[n+1] nat = list (list^[n] nat)
Bernd Losert (Feb 20 2022 at 11:25):
OK. Let me define my own nat.iterate
then and see if that helps.
Reid Barton (Feb 20 2022 at 11:26):
Maybe you can also work with this definition by also generalizing over the types nat
and string
and the function f
, and writing something like | (n + 1) f xs := ex n (list.map f) xs
Reid Barton (Feb 20 2022 at 11:28):
I feel like one of these is less efficient than the other, but I'm not sure which or whether that matters to you.
Bernd Losert (Feb 20 2022 at 11:40):
Progress!
def iter (f : α → α) : ∀ n : ℕ, α → α
| 0 := id
| (n + 1) := λ a, f (iter n a)
def ex (f : ℕ → string) : ∀ n : ℕ, (iter list n nat) → (iter list n string)
| (0) n := f n
| (n + 1) [] := []
| (n + 1) (m :: ms) := ex n m :: list.map (ex n) ms
Reid Barton (Feb 20 2022 at 11:42):
You should be able to use list.map
in the (n + 1)
case without doing a case split on the list as well.
Bernd Losert (Feb 20 2022 at 11:45):
Good catch. Thanks a lot.
Bernd Losert (Feb 20 2022 at 11:46):
If I have a proof of list^[n+1] nat = list (list^[n] nat)
, could I use that with the nat.iterate
version somehow?
Bernd Losert (Feb 20 2022 at 18:07):
So I tried to generalize the ex
example, but it doesn't work:
variables {α β : Type u}
variable {f : Type u → Type u}
def iter (f : α → α) : ∀ n : ℕ, α → α
| 0 := id
| (n + 1) := λ a, f (iter n a)
def map [functor f] (m : α → β) : ∀ n, iter f n α → iter f n β
| 0 val := m val
| (n + 1) val := functor.map (map n) val
Reid Barton (Feb 20 2022 at 18:09):
It's probably not obvious to Lean what functor you want to map
until you unfold iter
Bernd Losert (Feb 20 2022 at 18:11):
Yes. Should I pass the functor f
instance to functor.map
?
Bernd Losert (Feb 20 2022 at 18:11):
Yeah, that works.
Last updated: Dec 20 2023 at 11:08 UTC