Zulip Chat Archive
Stream: general
Topic: help dealing with cast on fin
Frederick Pu (Jan 08 2026 at 19:05):
Does anyone have any tips on how to prove a goal liek this?
vars : VarMap
name : Name
he✝ : (inferType vars (var name)).isSome = true
ctx : DVector (Array.map (fun x => x.snd.type) vars).toList
x : Fin (Array.size vars)
h : Array.findLastFinIdx? (fun x => x.fst == name) vars = some x
he : (Array.findLast? (fun x => decide (x.fst = name)) vars).isSome = true
this : x = (some x).get ⋯
⊢ ↑(cast ?m.88
(⟨Array.size vars - 1, ⋯⟩ - (cast ⋯ (Array.findFinIdx? (fun x => x.fst == name) (Array.reverse vars))).get ⋯)) =
Array.size vars - 1 - ↑((Array.findFinIdx? (fun x => decide (x.fst = name)) (Array.reverse vars)).get ⋯)
like i feel like we should be able to just strip away the cast and push the .val inside of the cast
Ruben Van de Velde (Jan 08 2026 at 19:09):
Not really, no. You might have more luck with a #mwe, but even then, maybe not much more. It looks suspicious that you have a metavariable ?m.88 in your cast, though
Aaron Liu (Jan 08 2026 at 21:31):
It should be possible to strip away the cast if it isn't an "evil" cast
Aaron Liu (Jan 08 2026 at 21:32):
how did you even end up with these casts in your goal?
Edward van de Meent (Jan 08 2026 at 21:34):
if instead of docs#cast you use docs#Fin.cast, i imagine that things will go a lot smoother...
Edward van de Meent (Jan 08 2026 at 21:42):
also, can i interest you in docs#Fin.last ?
Aaron Liu (Jan 08 2026 at 21:53):
can we have Fin.last take a [NeZero n] instead of returning a Fin (n + 1)
Violeta Hernández (Jan 09 2026 at 01:51):
Edward van de Meent said:
if instead of docs#cast you use docs#Fin.cast, i imagine that things will go a lot smoother...
I wonder if docs#Fin.cast_eq_cast should be reversed and made simp?
Edward van de Meent (Jan 09 2026 at 09:13):
I feel like that wouldn't trigger? I'm not sure though. Also, there is the usability issue of it being unable to simp when the rewrite already is with something like congr(Fin $h) : Fin n = Fin m. Strictly speaking that's not a reason against the simp lemma, but it does seem to me like it would make bad (beginner) UX?
Aaron Liu (Jan 09 2026 at 11:17):
well the special case of Fin is nice because it's injective
Frederick Pu (Jan 09 2026 at 22:09):
I switched to using Fin.cast and now the metavariable is gone:
vars : VarMap
name : Name
he✝ : (inferType vars (var name)).isSome = true
ctx : DVector (Array.map (fun x => x.snd.type) vars).toList
x : Fin (Array.size vars)
h : Array.findLastFinIdx? (fun x => x.fst == name) vars = some x
he : (Array.findLast? (fun x => decide (x.fst = name)) vars).isSome = true
this : x = (some x).get ⋯
⊢ ↑(⟨Array.size vars - 1, ⋯⟩ - Fin.cast ⋯ ((Array.findFinIdx? (fun x => x.fst == name) (Array.reverse vars)).get ⋯)) =
Array.size vars - 1 - ↑((Array.findFinIdx? (fun x => decide (x.fst = name)) (Array.reverse vars)).get ⋯)
Aaron Liu (Jan 09 2026 at 22:16):
maybe it's just hidden
Frederick Pu (Jan 09 2026 at 22:17):
it's weird that it's hidden for Fin.cast and not cast
Frederick Pu (Jan 09 2026 at 22:18):
is there a sense in which cast is less proof irrelevant?
Aaron Liu (Jan 09 2026 at 22:23):
I mean the pretty printer may have hidden it behind the ⋯
Frederick Pu (Jan 09 2026 at 22:24):
yeah i just dont understand why the pretty printer doesnt do that for cast also?
Frederick Pu (Jan 09 2026 at 22:27):
also i think this might be a bug with grind
Frederick Pu (Jan 09 2026 at 22:27):
def Array.findLastFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) := Option.map (fun res => ⟨as.size - 1, by {
have := res.isLt
grind
}⟩ - Fin.cast (size_reverse) res) (as.reverse.findFinIdx? p)
Frederick Pu (Jan 09 2026 at 22:27):
but when i do
def Array.findLastFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) := Option.map (fun res => ⟨as.size - 1, by {
grind [res.isLt]
}⟩ - Fin.cast (size_reverse) res) (as.reverse.findFinIdx? p)
i get:
redundant parameter `res.isLt`, `grind` uses local hypotheses automaticallyLean 4
Frederick Pu (Jan 09 2026 at 22:28):
but then this:
def Array.findLastFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) := Option.map (fun res => ⟨as.size - 1, by {
grind
}⟩ - Fin.cast (size_reverse) res) (as.reverse.findFinIdx? p)
gives:
`grind` failed
case grind.2
α : Type u
p : α → Bool
as : Array α
res : Fin as.reverse.size
h : as.size ≤ as.size - 1
h_1 : ¬-1 * ↑as.size + 1 ≤ 0
⊢ False
(trace)Lean 4
Frederick Pu (Jan 09 2026 at 22:37):
also here's a version of Fin.last that uses NeZero instead:
def Fin.last' {n : Nat} [NeZero n] : Fin n :=
match h : n with
| (k + 1) => Fin.last k
| 0 => by {
apply False.elim
expose_names
rw [h] at inst
simp at inst
}
def Fin.val_last'_eq {n : Nat} [NeZero n] : (Fin.last' (n := n)).val = n - 1 := sorry
def Fin.le_last' {n : Nat} [NeZero n] : ∀ i : Fin n, i ≤ (Fin.last' (n := n)) := sorry
def Array.findLast? {α : Type u} (p : α → Bool) (as : Array α) : Option α := as.reverse.find? p
Frederick Pu (Jan 10 2026 at 20:15):
btw I was able to close the sorry thanks everyone for your help
Last updated: Feb 28 2026 at 14:05 UTC