Skip to content

Commit 747ea85

Browse files
authored
feat: extensional hash maps (leanprover#8004)
This PR adds extensional hash maps and hash sets under the names `Std.ExtDHashMap`, `Std.ExtHashMap` and `Std.ExtHashSet`. Extensional hash maps work like regular hash maps, except that they have extensionality lemmas which make them easier to use in proofs. This however makes it also impossible to regularly iterate over its entries.
1 parent 2ba021e commit 747ea85

25 files changed

Lines changed: 7477 additions & 59 deletions

src/Init/Core.lean

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,34 @@ term.
938938
theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → HEq (Eq.recOn (motive := fun x _ => φ x) h p) p
939939
| rfl, p => HEq.refl p
940940

941+
/--
942+
Heterogenous equality with an `Eq.rec` application on the left is equivalent to a heterogenous
943+
equality on the original term.
944+
-/
945+
theorem eqRec_heq_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v}
946+
{b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} :
947+
HEq (@Eq.rec α a motive refl b h) c ↔ HEq refl c :=
948+
h.rec (fun _ => ⟨id, id⟩) c
949+
950+
/--
951+
Heterogenous equality with an `Eq.rec` application on the right is equivalent to a heterogenous
952+
equality on the original term.
953+
-/
954+
theorem heq_eqRec_iff {α : Sort u} {a : α} {motive : (b : α) → a = b → Sort v}
955+
{b : α} {refl : motive a (Eq.refl a)} {h : a = b} {c : motive b h} :
956+
HEq c (@Eq.rec α a motive refl b h) ↔ HEq c refl :=
957+
h.rec (fun _ => ⟨id, id⟩) c
958+
959+
/--
960+
Moves an cast using `Eq.rec` from the function to the argument.
961+
Note: because the motive isn't reliably detected by unification,
962+
it needs to be provided as an explicit parameter.
963+
-/
964+
theorem apply_eqRec {α : Sort u} {a : α} (motive : (b : α) → a = b → Sort v)
965+
{b : α} {h : a = b} {c : motive a (Eq.refl a) → β} {d : motive b h} :
966+
@Eq.rec α a (fun b h => motive b h → β) c b h d = c (h.symm ▸ d) := by
967+
cases h; rfl
968+
941969
/--
942970
If casting a term with `Eq.rec` to another type makes it equal to some other term, then the two
943971
terms are heterogeneously equal.
@@ -983,7 +1011,7 @@ theorem HEq.comm {a : α} {b : β} : HEq a b ↔ HEq b a := Iff.intro HEq.symm H
9831011
theorem heq_comm {a : α} {b : β} : HEq a b ↔ HEq b a := HEq.comm
9841012

9851013
@[symm] theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp
986-
theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm
1014+
theorem Iff.comm : (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm
9871015
theorem iff_comm : (a ↔ b) ↔ (b ↔ a) := Iff.comm
9881016

9891017
@[symm] theorem And.symm : a ∧ b → b ∧ a := fun ⟨ha, hb⟩ => ⟨hb, ha⟩
@@ -1148,12 +1176,12 @@ theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) :
11481176
| isTrue _ => rfl
11491177
| isFalse _ => rfl
11501178

1151-
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
1179+
instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e) :=
11521180
match dC with
11531181
| isTrue _ => dT
11541182
| isFalse _ => dE
11551183

1156-
instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
1184+
instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h) :=
11571185
match dC with
11581186
| isTrue hc => dT hc
11591187
| isFalse hc => dE hc
@@ -1869,9 +1897,7 @@ protected abbrev hrecOn
18691897
(f : (a : α) → motive (Quot.mk r a))
18701898
(c : (a b : α) → (p : r a b) → HEq (f a) (f b))
18711899
: motive q :=
1872-
Quot.recOn q f fun a b p => eq_of_heq <|
1873-
have p₁ : HEq (Eq.ndrec (f a) (sound p)) (f a) := eqRec_heq (sound p) (f a)
1874-
HEq.trans p₁ (c a b p)
1900+
Quot.recOn q f fun a b p => eq_of_heq (eqRec_heq_iff.mpr (c a b p))
18751901

18761902
end
18771903
end Quot
@@ -2234,6 +2260,27 @@ theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
22342260
show extfunApp (Quot.mk eqv f) = extfunApp (Quot.mk eqv g)
22352261
exact congrArg extfunApp (Quot.sound h)
22362262

2263+
/--
2264+
Like `Quot.liftOn q f h` but allows `f a` to "know" that `q = Quot.mk r a`.
2265+
-/
2266+
protected abbrev Quot.pliftOn {α : Sort u} {r : α → α → Prop}
2267+
(q : Quot r)
2268+
(f : (a : α) → q = Quot.mk r a → β)
2269+
(h : ∀ (a b : α) (h h'), r a b → f a h = f b h') : β :=
2270+
q.rec (motive := fun q' => q = q' → β) f
2271+
(fun a b p => funext fun h' =>
2272+
(apply_eqRec (motive := fun b _ => q = b)).trans
2273+
(@h a b (h'.trans (sound p).symm) h' p)) rfl
2274+
2275+
/--
2276+
Like `Quotient.liftOn q f h` but allows `f a` to "know" that `q = Quotient.mk s a`.
2277+
-/
2278+
protected abbrev Quotient.pliftOn {α : Sort u} {s : Setoid α}
2279+
(q : Quotient s)
2280+
(f : (a : α) → q = Quotient.mk s a → β)
2281+
(h : ∀ (a b : α) (h h'), a ≈ b → f a h = f b h') : β :=
2282+
Quot.pliftOn q f h
2283+
22372284
instance Pi.instSubsingleton {α : Sort u} {β : α → Sort v} [∀ a, Subsingleton (β a)] :
22382285
Subsingleton (∀ a, β a) where
22392286
allEq f g := funext fun a => Subsingleton.elim (f a) (g a)

src/Std/Data.lean

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ import Std.Data.HashSet
1010
import Std.Data.DTreeMap
1111
import Std.Data.TreeMap
1212
import Std.Data.TreeSet
13+
import Std.Data.ExtDHashMap
14+
import Std.Data.ExtHashMap
15+
import Std.Data.ExtHashSet
1316

1417
-- The imports above only import the modules needed to work with the version which bundles
1518
-- the well-formedness invariant, so we need to additionally import the files that deal with the

src/Std/Data/DHashMap/Basic.lean

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Lemmas about the operations on `Std.Data.DHashMap` are available in the
1818
module `Std.Data.DHashMap.Lemmas`.
1919
2020
See the module `Std.Data.DHashMap.Raw` for a variant of this type which is safe to use in
21-
nested inductive types.
21+
nested inductive types and the module `Std.Data.ExtDHashMap` for a variant with extensionality.
2222
2323
For implementation notes, see the docstring of the module `Std.Data.DHashMap.Internal.Defs`.
2424
-/
@@ -54,9 +54,12 @@ should be an equivalence relation and `a == b` should imply `hash a = hash b` (s
5454
instance is lawful, i.e., if `a == b` implies `a = b`.
5555
5656
These hash maps contain a bundled well-formedness invariant, which means that they cannot
57-
be used in nested inductive types. For these use cases, `Std.Data.DHashMap.Raw` and
58-
`Std.Data.DHashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer
57+
be used in nested inductive types. For these use cases, `Std.DHashMap.Raw` and
58+
`Std.DHashMap.Raw.WF` unbundle the invariant from the hash map. When in doubt, prefer
5959
`DHashMap` over `DHashMap.Raw`.
60+
61+
For a variant that is more convenient for use in proofs because of extensionalities, see
62+
`Std.ExtDHashMap` which is defined in the module `Std.Data.ExtDHashMap`.
6063
-/
6164
def DHashMap (α : Type u) (β : α → Type v) [BEq α] [Hashable α] := { m : DHashMap.Raw α β // m.WF }
6265

src/Std/Data/DHashMap/Internal/RawLemmas.lean

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,8 +1178,6 @@ theorem foldRevM_eq_foldrM_toList [Monad m'] [LawfulMonad m']
11781178
{f : δ → α → β → m' δ} {init : δ} :
11791179
Raw.Internal.foldRevM f init m.1 =
11801180
(Raw.Const.toList m.1).foldrM (fun a b => f b a.1 a.2) init := by
1181-
have :=Raw.foldRevM_eq_foldrM_toListModel (m := m') (b := m.1) (init := init) (f := f)
1182-
11831181
simp_to_model [foldRevM, Const.toList] using List.foldrM_eq_foldrM_toProd'
11841182

11851183
theorem foldRev_eq_foldr_toList {f : δ → α → β → δ} {init : δ} :
@@ -1199,6 +1197,16 @@ end Const
11991197

12001198
end monadic
12011199

1200+
section insertMany
1201+
1202+
variable {ρ : Type w} [ForIn Id ρ ((a : α) × β a)]
1203+
1204+
@[elab_as_elim]
1205+
theorem insertMany_ind {motive : Raw₀ α β → Prop} (m : Raw₀ α β) (l : ρ)
1206+
(init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) :
1207+
motive (m.insertMany l).1 :=
1208+
(m.insertMany l).2 motive (insert _ _ _) init
1209+
12021210
@[simp]
12031211
theorem insertMany_nil :
12041212
m.insertMany [] = m := by
@@ -1227,6 +1235,14 @@ theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] (
12271235
(m.insertMany l).1.contains k → (l.map Sigma.fst).contains k = false → m.contains k := by
12281236
simp_to_model [insertMany, contains] using List.containsKey_of_containsKey_insertList
12291237

1238+
theorem contains_insertMany_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1239+
{l : ρ} {k : α} (h' : m.contains k) : (m.insertMany l).1.contains k := by
1240+
refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1
1241+
refine insertMany_ind m l ⟨h', h⟩ ?_
1242+
intro m a b ⟨h', h⟩
1243+
simp only [h, contains_insert, h', Bool.or_true, true_and]
1244+
exact h.insert₀
1245+
12301246
theorem get?_insertMany_list_of_contains_eq_false [LawfulBEq α] (h : m.1.WF)
12311247
{l : List ((a : α) × β a)} {k : α}
12321248
(h' : (l.map Sigma.fst).contains k = false) :
@@ -1352,6 +1368,15 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.
13521368
m.1.size ≤ (m.insertMany l).1.1.size := by
13531369
simp_to_model [insertMany, size] using List.length_le_length_insertList
13541370

1371+
theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1372+
{l : ρ} : m.1.size ≤ (m.insertMany l).1.1.size := by
1373+
refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1
1374+
refine insertMany_ind m l ⟨Nat.le_refl _, h⟩ ?_
1375+
intro m' a b ⟨h', h⟩
1376+
constructor
1377+
· exact Nat.le_trans h' (size_le_size_insert m' h)
1378+
· exact h.insert₀
1379+
13551380
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
13561381
{l : List ((a : α) × β a)} :
13571382
(m.insertMany l).1.1.size ≤ m.1.size + l.length := by
@@ -1363,9 +1388,26 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
13631388
(m.insertMany l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
13641389
simp_to_model [insertMany, isEmpty] using List.isEmpty_insertList
13651390

1391+
theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1392+
{l : ρ} : (m.insertMany l).1.1.isEmpty → m.1.isEmpty := by
1393+
refine (?_ : _ ∧ (m.insertMany l).1.1.WF).1
1394+
refine insertMany_ind m l ⟨id, h⟩ ?_
1395+
intro m' a b ⟨h', h⟩
1396+
constructor
1397+
· intro h''
1398+
simp only [isEmpty_insert, h, Bool.false_eq_true] at h''
1399+
· exact h.insert₀
1400+
13661401
namespace Const
13671402

13681403
variable {β : Type v} (m : Raw₀ α (fun _ => β))
1404+
variable {ρ : Type w} [ForIn Id ρ (α × β)]
1405+
1406+
@[elab_as_elim]
1407+
theorem insertMany_ind {motive : Raw₀ α (fun _ => β) → Prop} (m : Raw₀ α fun _ => β) (l : ρ)
1408+
(init : motive m) (insert : ∀ m a b, motive m → motive (m.insert a b)) :
1409+
motive (insertMany m l).1 :=
1410+
(insertMany m l).2 motive (insert _ _ _) init
13691411

13701412
@[simp]
13711413
theorem insertMany_nil :
@@ -1395,6 +1437,14 @@ theorem contains_of_contains_insertMany_list [EquivBEq α] [LawfulHashable α] (
13951437
(insertMany m l).1.contains k → (l.map Prod.fst).contains k = false → m.contains k := by
13961438
simp_to_model [Const.insertMany, contains] using List.containsKey_of_containsKey_insertListConst
13971439

1440+
theorem contains_insertMany_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1441+
{l : ρ} {k : α} (h' : m.contains k) : (insertMany m l).1.contains k := by
1442+
refine (?_ : _ ∧ (insertMany m l).1.1.WF).1
1443+
refine insertMany_ind m l ⟨h', h⟩ ?_
1444+
intro m a b ⟨h', h⟩
1445+
simp only [h, contains_insert, h', Bool.or_true, true_and]
1446+
exact h.insert₀
1447+
13981448
theorem getKey?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
13991449
{l : List (α × β)} {k : α}
14001450
(h' : (l.map Prod.fst).contains k = false) :
@@ -1466,6 +1516,15 @@ theorem size_le_size_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.
14661516
m.1.size ≤ (insertMany m l).1.1.size := by
14671517
simp_to_model [Const.insertMany, size] using List.length_le_length_insertListConst
14681518

1519+
theorem size_le_size_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1520+
{l : ρ} : m.1.size ≤ (insertMany m l).1.1.size := by
1521+
refine (?_ : _ ∧ (insertMany m l).1.1.WF).1
1522+
refine insertMany_ind m l ⟨Nat.le_refl _, h⟩ ?_
1523+
intro m' a b ⟨h', h⟩
1524+
constructor
1525+
· exact Nat.le_trans h' (size_le_size_insert m' h)
1526+
· exact h.insert₀
1527+
14691528
theorem size_insertMany_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
14701529
{l : List (α × β)} :
14711530
(insertMany m l).1.1.size ≤ m.1.size + l.length := by
@@ -1477,6 +1536,16 @@ theorem isEmpty_insertMany_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
14771536
(insertMany m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
14781537
simp_to_model [Const.insertMany, isEmpty] using List.isEmpty_insertListConst
14791538

1539+
theorem isEmpty_of_isEmpty_insertMany [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1540+
{l : ρ} : (insertMany m l).1.1.isEmpty → m.1.isEmpty := by
1541+
refine (?_ : _ ∧ (insertMany m l).1.1.WF).1
1542+
refine insertMany_ind m l ⟨id, h⟩ ?_
1543+
intro m' a b ⟨h', h⟩
1544+
constructor
1545+
· intro h''
1546+
simp only [isEmpty_insert, h, Bool.false_eq_true] at h''
1547+
· exact h.insert₀
1548+
14801549
theorem get?_insertMany_list_of_contains_eq_false [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
14811550
{l : List (α × β)} {k : α}
14821551
(h' : (l.map Prod.fst).contains k = false) :
@@ -1532,6 +1601,15 @@ theorem getD_insertMany_list_of_mem [EquivBEq α] [LawfulHashable α] (h : m.1.W
15321601

15331602
variable (m : Raw₀ α (fun _ => Unit))
15341603

1604+
variable {ρ : Type w} [ForIn Id ρ α]
1605+
1606+
@[elab_as_elim]
1607+
theorem insertManyIfNewUnit_ind {motive : Raw₀ α (fun _ => Unit) → Prop}
1608+
(m : Raw₀ α fun _ => Unit) (l : ρ)
1609+
(init : motive m) (insert : ∀ m a, motive m → motive (m.insertIfNew a ())) :
1610+
motive (insertManyIfNewUnit m l).1 :=
1611+
(insertManyIfNewUnit m l).2 motive (insert _ _) init
1612+
15351613
@[simp]
15361614
theorem insertManyIfNewUnit_nil :
15371615
insertManyIfNewUnit m [] = m := by
@@ -1561,6 +1639,14 @@ theorem contains_of_contains_insertManyIfNewUnit_list [EquivBEq α] [LawfulHasha
15611639
simp_to_model [Const.insertManyIfNewUnit, contains]
15621640
using List.containsKey_of_containsKey_insertListIfNewUnit
15631641

1642+
theorem contains_insertManyIfNewUnit_of_contains [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1643+
{l : ρ} {k : α} (h' : m.contains k) : (insertManyIfNewUnit m l).1.contains k := by
1644+
refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1
1645+
refine insertManyIfNewUnit_ind m l ⟨h', h⟩ ?_
1646+
intro m a ⟨h', h⟩
1647+
simp only [h, contains_insertIfNew, h', Bool.or_true, true_and]
1648+
exact h.insertIfNew₀
1649+
15641650
theorem getKey?_insertManyIfNewUnit_list_of_contains_eq_false_of_contains_eq_false
15651651
[EquivBEq α] [LawfulHashable α]
15661652
(h : m.1.WF) {l : List α} {k : α} :
@@ -1652,6 +1738,15 @@ theorem size_le_size_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α]
16521738
m.1.size ≤ (insertManyIfNewUnit m l).1.1.size := by
16531739
simp_to_model [Const.insertManyIfNewUnit, size] using List.length_le_length_insertListIfNewUnit
16541740

1741+
theorem size_le_size_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1742+
{l : ρ} : m.1.size ≤ (insertManyIfNewUnit m l).1.1.size := by
1743+
refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1
1744+
refine insertManyIfNewUnit_ind m l ⟨Nat.le_refl _, h⟩ ?_
1745+
intro m' a ⟨h', h⟩
1746+
constructor
1747+
· exact Nat.le_trans h' (size_le_size_insertIfNew m' h)
1748+
· exact h.insertIfNew₀
1749+
16551750
theorem size_insertManyIfNewUnit_list_le [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
16561751
{l : List α} :
16571752
(insertManyIfNewUnit m l).1.1.size ≤ m.1.size + l.length := by
@@ -1663,6 +1758,16 @@ theorem isEmpty_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h :
16631758
(insertManyIfNewUnit m l).1.1.isEmpty = (m.1.isEmpty && l.isEmpty) := by
16641759
simp_to_model [Const.insertManyIfNewUnit, isEmpty] using List.isEmpty_insertListIfNewUnit
16651760

1761+
theorem isEmpty_of_isEmpty_insertManyIfNewUnit [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
1762+
{l : ρ} : (insertManyIfNewUnit m l).1.1.isEmpty → m.1.isEmpty := by
1763+
refine (?_ : _ ∧ (insertManyIfNewUnit m l).1.1.WF).1
1764+
refine insertManyIfNewUnit_ind m l ⟨id, h⟩ ?_
1765+
intro m' a ⟨h', h⟩
1766+
constructor
1767+
· intro h''
1768+
simp only [isEmpty_insertIfNew, h, Bool.false_eq_true] at h''
1769+
· exact h.insertIfNew₀
1770+
16661771
theorem get?_insertManyIfNewUnit_list [EquivBEq α] [LawfulHashable α] (h : m.1.WF)
16671772
{l : List α} {k : α} :
16681773
get? (insertManyIfNewUnit m l).1 k =
@@ -2329,6 +2434,8 @@ abbrev getD_insertManyIfNewUnit_empty_list := @getD_insertManyIfNewUnit_emptyWit
23292434

23302435
end Const
23312436

2437+
end insertMany
2438+
23322439
section Alter
23332440

23342441
theorem isEmpty_alter_eq_isEmpty_erase [LawfulBEq α] (h : m.1.WF) {k : α}
@@ -3069,10 +3176,20 @@ theorem modify_equiv_congr (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) (h : m₁.1 ~m
30693176
{k : α} (f : β → β) : (modify m₁ k f).1 ~m (modify m₂ k f).1 := by
30703177
simp_to_model [Equiv, Const.modify] using List.Const.modifyKey_of_perm _ h.1
30713178

3179+
theorem equiv_of_forall_getKey_eq_of_forall_get?_eq (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) :
3180+
(∀ k hk hk', m₁.getKey k hk = m₂.getKey k hk') → (∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by
3181+
simp_to_model [getKey, Const.get?, contains, Equiv] using List.getKey_getValue?_ext
3182+
3183+
@[deprecated equiv_of_forall_getKey_eq_of_forall_get?_eq (since := "2025-04-25")]
30723184
theorem equiv_of_forall_getKey?_eq_of_forall_get?_eq (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) :
30733185
(∀ k, m₁.getKey? k = m₂.getKey? k) → (∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by
30743186
simp_to_model [getKey?, Const.get?, Equiv] using List.getKey?_getValue?_ext
30753187

3188+
theorem equiv_of_forall_get?_eq {α : Type u} [BEq α] [Hashable α] [LawfulBEq α]
3189+
{m₁ m₂ : Raw₀ α fun _ => β} (h₁ : m₁.1.WF) (h₂ : m₂.1.WF) :
3190+
(∀ k, get? m₁ k = get? m₂ k) → m₁.1 ~m m₂.1 := by
3191+
simpa only [Const.get?_eq_get?, h₁, h₂] using Raw₀.equiv_of_forall_get?_eq m₁ m₂ h₁ h₂
3192+
30763193
theorem equiv_of_forall_getKey?_unit_eq {m₁ m₂ : Raw₀ α fun _ => Unit}
30773194
(h₁ : m₁.1.WF) (h₂ : m₂.1.WF) : (∀ k, m₁.getKey? k = m₂.getKey? k) → m₁.1 ~m m₂.1 := by
30783195
simp_to_model [getKey?, Equiv] using List.getKey?_ext

0 commit comments

Comments
 (0)