Zulip Chat Archive
Stream: new members
Topic: Array and other beginner questions
Tom (Sep 16 2024 at 20:39):
Hi,
After a couple of years, I finally have time to come back to Lean. I'm re-reading the docs and David Christiansen's FPiL and just experimenting with some trivial code. I would appreciate any help with my questions below:
1) Why does the for
syntax require a Nat
rather than just a numeric type? (And I would hope/expect ii
to be of that type).
def fill_arr1 (n : UInt64) : Id (Array UInt64) := do
let mut a := Array.mkEmpty (α := UInt64) n.toNat
for i in [0:n.toNat] do --< Here - why can't I say `n`
a := a.push (UInt64.ofNat i) --< ... and now I have to do a conversion
pure a
2) Speaking of for
, my understanding is that this is just a syntax /macro. Is there a way to jump to its definition (VS Code)? I don't seem to be able to find it.
I also added the following (somewhat non-sensical) code:
def fill_arr2 (n : UInt64) : Id (Array UInt64) := do
let mut a := fill_arr1 n
for i in [0:a.size] do
if h: i < a.size then
let jj : Fin a.size := ⟨i, h⟩;
a := a.set jj 10
pure a
3) Why does a.size
return a Nat
rather than a Fin a.size
type? That way (and in combination with the for
question) I seem to be forced to do unnecessary checking and conversions.
4) Is there a way to "hoist" the a.size
check outsize of the loop rather than doing it on every element access? I understand perhaps I could use a higher-order approach like a fold etc, but I can't see how to do it with this style of programming.
5) Is there a way to "reuse" a.size
, e.g.
def fill_arr3 (n : UInt64) : Id (Array UInt64) := do
let mut a := fill_arr1 n
let as := a.size
for i in [0:as] do
if h: i < as then
let jj : Fin as := ⟨i, h⟩;
a := a.set jj 10 --< This line is not happy
pure a
I kind of "get" why this doesn't work but this makes me think of something like abbrev
at the top level.
Sorry for all the questions and thank you for your help!
Tom
Eric Wieser (Sep 16 2024 at 21:14):
Tom said:
Why does
a.size
return aNat
rather than aFin a.size
type? That way (and in combination with thefor
question) I seem to be forced to do unnecessary checking and conversions.
This wouldn't make sense, because Fin a.size
only goes up to a.size - 1
. Perhaps you want the for h : i in [0:a.size] do
syntax instead, but I think in your example you're still in trouble because the a.size
in the first loop might not be the same as the next loop
Eric Wieser (Sep 16 2024 at 21:17):
This works:
import Batteries
def fill_arr1 (n : UInt64) : Id (Array UInt64) := do
let mut a := Array.mkEmpty (α := UInt64) n.toNat
for i in [0:n.toNat] do --< Here - why can't I say `n`
a := a.push (UInt64.ofNat i) --< ... and now I have to do a conversion
pure a
def fill_arr2 (n : UInt64) : Id (Array UInt64) := do
let mut a : Batteries.Vector _ _ := ⟨fill_arr1 n, rfl⟩
for h : i in [0:a.size] do
let jj : Fin a.size := ⟨i, h.2⟩
a := a.set jj 10
pure a.toArray
Eric Wieser (Sep 16 2024 at 21:17):
The trick here is that Batteries.Vector
promises up front that the size remains unchanged on each loop iteration
Tom (Sep 16 2024 at 21:38):
Hi @Eric Wieser ,
Thank for your help. I appreciate you pointing out the fallacy with Fin
. I guess I confused myself wondering about my question 2) about the return type of for
(e.g. returning Fin
instead of Nat) and then trying to shoe-horn that in.
I was not aware of the for h:...
syntax, thanks for pointing that out.
because the
a.size
in the first loop might not be the same as the next loop
I am not sure if you mean this "in general" (in which case I agree), or in the specific example of my original fill_arr2
(in which case I'm not sure I understand).
Thank you!
Eric Wieser (Sep 16 2024 at 22:28):
I indeed mean in general, but if you want to tell Lean that in your specific example it's fine, you need to bundle that proof with a
, which is exactly what you get from Vector there
Last updated: May 02 2025 at 03:31 UTC