Zulip Chat Archive
Stream: lean4
Topic: Array gripes
James Gallicchio (Nov 02 2023 at 17:57):
this is a complain-y thread, but I am hoping to learn something:
The design of Array
and GetElem
just makes me feel like it's working against me in the realm of proof. Just as an example (all of these are with Std
imported):
abbrev mem (x : α) (A : Array α) := ∃ i : Fin A.size, A[i] = x
example : ¬(mem x #[]) := by simp; intros; sorry
I didn't try very hard to prove this, but it also shouldn't be hard to prove this?
and you might ask, James, why are you using a non-standard definition of mem on arrays?? well, because this doesn't compile:
example : ¬(x ∈ (#[] : Array α)) := by sorry
because the Membership
instance (from core!) requires DecidableEq
for some reason. okay fine, let's weaken the statement then:
example (x : α) [DecidableEq α] : ¬(x ∈ (#[] : Array α)) := by sorry
but proving this requires digging into very complicated definitions. I know that the answer is probably "add more simp lemmas", but I'm really struggling to blindly believe this is the right solution, compared with re-thinking our approach.
thoughts or hope would be appreciated.
David Renshaw (Nov 02 2023 at 18:05):
abbrev mem (x : α) (A : Array α) := ∃ i : Fin A.size, A[i] = x
example : ¬(mem x #[]) := by
simp
intros y
cases Nat.not_succ_le_zero (↑y) y.prop
James Gallicchio (Nov 02 2023 at 18:08):
ok, if you want an example that doesn't have an escape hatch from digging through the expressions:
example (x y : A) : x ≠ y → ¬(mem x #[y]) := by
simp
intros y
sorry
James Gallicchio (Nov 02 2023 at 18:09):
(or maybe I should generalize further to Array.push
so that you can't just case on the value of Fin 1
)
James Gallicchio (Nov 02 2023 at 18:11):
contrast with list, where simp can just do it:
example (x y : A) : x ≠ y → ¬(x ∈ [y]) := by simp
example (xs : List A) (x y : A) : ¬(x ∈ xs) → x ≠ y → (¬ x ∈ xs ++ [y]) := by
intros; simp [*]
Kyle Miller (Nov 02 2023 at 18:12):
I can't see why DecidableEq
is necessary -- the type of docs#Array.instMembershipArray doesn't require it... If you check the term, the DecidableEq
instance doesn't even appear.
James Gallicchio (Nov 02 2023 at 18:12):
then that must have changed since 4.2.0-rc1
Kyle Miller (Nov 02 2023 at 18:13):
I'm not saying I'm not seeing the same behavior
Kyle Miller (Nov 02 2023 at 18:14):
It seems like the real issue is some interaction with autoImplicit
Kyle Miller (Nov 02 2023 at 18:15):
Try this:
example (x : α) : ¬(x ∈ (#[] : Array α)) := by
sorry
James Gallicchio (Nov 02 2023 at 18:16):
oh, Joachim just changed this 4 days ago
James Gallicchio (Nov 02 2023 at 18:16):
https://github.com/leanprover/lean4/pull/2774
Kyle Miller (Nov 02 2023 at 18:16):
Oh, so he did (I just checked the blame)
Kyle Miller (Nov 02 2023 at 18:18):
Still, even with this change, I found that adding DecidableEq
somehow made it go through, as did adding (x : α)
, or adding a variable
line to introduce α
Kyle Miller (Nov 02 2023 at 18:22):
Re Array and GetElem, it seems worth adding the Array version of docs#List.mem_iff_get so that you can go back and forth between your Exists formulation and the main definition.
James Gallicchio (Nov 02 2023 at 18:25):
well, the new definition is also fine for my use case, because I can write a lemma that Array.push A x = Array.ofList (A.toList ++ [x])
. But I'd prefer if that lemma were simp
.
Jun Yoshida (Nov 03 2023 at 03:15):
Oh, I didn't know the membership relation on Array
was changed. I agree that DecidableEq
-free version is appreciated, but this is a serious breaking change (wrt my personal projects).
Specifically, the change drops the link between Membership
and Array.contains
, so I need to replace code like
if h : n ∈ #[1,2,3] then sorry else sorry
to the ones using Array.contains
.
So, I would like to ask if there is any plan that the core / Std has theorem like this:
theorem Array.mem_iff_contains
{α : Type _} [DecidableEq α] {a : α} {as : Array α} :
a ∈ as ↔ as.contains a :=
sorry
The following is my solution extracted from my project (I hide it since it's huge), but I hesitate to make PR on it since the code is not clean and contains a bunch of materials.
Proof of Array.mem_iff_contains
Mario Carneiro (Nov 03 2023 at 03:16):
This should definitely be a theorem in Std (we shouldn't have shipped without it, sorry)
Mario Carneiro (Nov 03 2023 at 03:19):
In fact it seems there isn't even a decidable instance? That theorem would need to be part of it
Jun Yoshida (Nov 03 2023 at 03:23):
Mario Carneiro said:
In fact it seems there isn't even a decidable instance? That theorem would need to be part of it
I hope that Decidable (a ∈ #[1,2,3])
wouldn't go through Array.toList
but just use Array.contains
since the former is way slow. That is one reason we need Array.mem_iff_contains
above.
Mario Carneiro (Nov 03 2023 at 03:28):
yes, that's what I mean
Jun Yoshida (Nov 03 2023 at 03:44):
I see, thanks. I just wanted to make sure I understand the situation correctly.
Mario Carneiro (Nov 03 2023 at 03:45):
I'll push a fix soon
Mario Carneiro (Nov 03 2023 at 05:44):
@Jun Yoshida fixed
Jun Yoshida (Nov 03 2023 at 05:53):
@Mario Carneiro Great! Thank you for all your efforts making the fix so quickly.
Last updated: Dec 20 2023 at 11:08 UTC