3
3
--
4
4
-- An equational reasoning library for propositional equality over
5
5
-- vectors of different indices using cast.
6
+ --
7
+ -- To see example usages of this library, scroll to the `Combinators`
8
+ -- section.
6
9
------------------------------------------------------------------------
7
10
8
11
{-# OPTIONS --cubical-compatible --safe #-}
9
12
10
13
module README.Data.Vec.Relation.Binary.Equality.Cast where
11
14
12
15
open import Agda.Primitive
13
- open import Data.List.Base as L using (List)
14
- import Data.List.Properties as Lₚ
16
+ open import Data.List.Base as List using (List)
17
+ import Data.List.Properties as List
15
18
open import Data.Nat.Base
16
19
open import Data.Nat.Properties
17
20
open import Data.Vec.Base
18
21
open import Data.Vec.Properties
19
22
open import Data.Vec.Relation.Binary.Equality.Cast
20
23
open import Relation.Binary.PropositionalEquality
21
- using (_≡_; refl; trans; sym; cong; subst ; module ≡-Reasoning )
24
+ using (_≡_; refl; sym; cong; module ≡-Reasoning )
22
25
23
26
private variable
24
27
a : Level
@@ -27,10 +30,6 @@ private variable
27
30
xs ys zs ws : Vec A n
28
31
29
32
30
- -- To see example usages of this library, scroll to the combinators
31
- -- section.
32
-
33
-
34
33
------------------------------------------------------------------------
35
34
-- Motivation
36
35
--
@@ -60,20 +59,20 @@ private variable
60
59
-- Although `cast` makes it possible to prove vector identities by ind-
61
60
-- uction, the explicit type-casting nature poses a significant barrier
62
61
-- to code reuse in larger proofs. For example, consider the identity
63
- -- ‘fromList (xs L .∷ʳ x) ≡ (fromList xs) ∷ʳ x’ where `L ._∷ʳ_` is the
62
+ -- ‘fromList (xs List .∷ʳ x) ≡ (fromList xs) ∷ʳ x’ where `List ._∷ʳ_` is the
64
63
-- snoc function of lists. We have
65
64
--
66
- -- fromList (xs L .∷ʳ x) : Vec A (L .length (xs L .∷ʳ x))
65
+ -- fromList (xs List .∷ʳ x) : Vec A (List .length (xs List .∷ʳ x))
67
66
-- = {- by definition -}
68
- -- fromList (xs L .++ L .[ x ]) : Vec A (L .length (xs L .++ L .[ x ]))
67
+ -- fromList (xs List .++ List .[ x ]) : Vec A (List .length (xs List .++ List .[ x ]))
69
68
-- = {- by fromList-++ -}
70
- -- fromList xs ++ fromList L .[ x ] : Vec A (L .length xs + L .length [ x ])
69
+ -- fromList xs ++ fromList List .[ x ] : Vec A (List .length xs + List .length [ x ])
71
70
-- = {- by definition -}
72
- -- fromList xs ++ [ x ] : Vec A (L .length xs + 1)
71
+ -- fromList xs ++ [ x ] : Vec A (List .length xs + 1)
73
72
-- = {- by unfold-∷ʳ -}
74
- -- fromList xs ∷ʳ x : Vec A (suc (L .length xs))
73
+ -- fromList xs ∷ʳ x : Vec A (suc (List .length xs))
75
74
-- where
76
- -- fromList-++ : cast _ (fromList (xs L .++ ys)) ≡ fromList xs ++ fromList ys
75
+ -- fromList-++ : cast _ (fromList (xs List .++ ys)) ≡ fromList xs ++ fromList ys
77
76
-- unfold-∷ʳ : cast _ (xs ∷ʳ x) ≡ xs ++ [ x ]
78
77
--
79
78
-- Although the identity itself is simple, the reasoning process changes
@@ -82,31 +81,42 @@ private variable
82
81
-- rearrange (the Agda version of) the identity into one with two
83
82
-- `cast`s, resulting in lots of boilerplate code as demonstrated by
84
83
-- `example1a-fromList-∷ʳ`.
85
- example1a-fromList-∷ʳ : ∀ (x : A) xs .(eq : L.length (xs L.∷ʳ x) ≡ suc (L.length xs)) →
86
- cast eq (fromList (xs L.∷ʳ x)) ≡ fromList xs ∷ʳ x
84
+ example1a-fromList-∷ʳ : ∀ (x : A) xs →
85
+ .(eq : List.length (xs List.∷ʳ x) ≡ suc (List.length xs)) →
86
+ cast eq (fromList (xs List.∷ʳ x)) ≡ fromList xs ∷ʳ x
87
87
example1a-fromList-∷ʳ x xs eq = begin
88
- cast eq (fromList (xs L.∷ʳ x)) ≡⟨⟩
89
- cast eq (fromList (xs L.++ L.[ x ])) ≡⟨ cast-trans eq₁ eq₂ (fromList (xs L.++ L.[ x ])) ⟨
90
- cast eq₂ (cast eq₁ (fromList (xs L.++ L.[ x ]))) ≡⟨ cong (cast eq₂) (fromList-++ xs) ⟩
91
- cast eq₂ (fromList xs ++ [ x ]) ≡⟨ ≈-sym (unfold-∷ʳ (sym eq₂) x (fromList xs)) ⟩
92
- fromList xs ∷ʳ x ∎
88
+ cast eq (fromList (xs List.∷ʳ x))
89
+ ≡⟨⟩
90
+ cast eq (fromList (xs List.++ List.[ x ]))
91
+ ≡⟨ cast-trans eq₁ eq₂ (fromList (xs List.++ List.[ x ])) ⟨
92
+ cast eq₂ (cast eq₁ (fromList (xs List.++ List.[ x ])))
93
+ ≡⟨ cong (cast eq₂) (fromList-++ xs) ⟩
94
+ cast eq₂ (fromList xs ++ [ x ])
95
+ ≡⟨ ≈-sym (unfold-∷ʳ (sym eq₂) x (fromList xs)) ⟩
96
+ fromList xs ∷ʳ x
97
+ ∎
93
98
where
94
99
open ≡-Reasoning
95
- eq₁ = Lₚ .length-++ xs {L .[ x ]}
96
- eq₂ = +-comm (L .length xs) 1
100
+ eq₁ = List .length-++ xs {List .[ x ]}
101
+ eq₂ = +-comm (List .length xs) 1
97
102
98
103
-- The `cast`s are irrelevant to core of the proof. At the same time,
99
104
-- they can be inferred from the lemmas used during the reasoning steps
100
105
-- (e.g. `fromList-++` and `unfold-∷ʳ`). To eliminate the boilerplate,
101
106
-- this library provides a set of equational reasoning combinators for
102
107
-- equality of the form `cast eq xs ≡ ys`.
103
- example1b-fromList-∷ʳ : ∀ (x : A) xs .(eq : L.length (xs L.∷ʳ x) ≡ suc (L.length xs)) →
104
- cast eq (fromList (xs L.∷ʳ x)) ≡ fromList xs ∷ʳ x
108
+ example1b-fromList-∷ʳ : ∀ (x : A) xs →
109
+ .(eq : List.length (xs List.∷ʳ x) ≡ suc (List.length xs)) →
110
+ cast eq (fromList (xs List.∷ʳ x)) ≡ fromList xs ∷ʳ x
105
111
example1b-fromList-∷ʳ x xs eq = begin
106
- fromList (xs L.∷ʳ x) ≈⟨⟩
107
- fromList (xs L.++ L.[ x ]) ≈⟨ fromList-++ xs ⟩
108
- fromList xs ++ [ x ] ≈⟨ unfold-∷ʳ (+-comm 1 (L.length xs)) x (fromList xs) ⟨
109
- fromList xs ∷ʳ x ∎
112
+ fromList (xs List.∷ʳ x)
113
+ ≈⟨⟩
114
+ fromList (xs List.++ List.[ x ])
115
+ ≈⟨ fromList-++ xs ⟩
116
+ fromList xs ++ [ x ]
117
+ ≈⟨ unfold-∷ʳ (+-comm 1 (List.length xs)) x (fromList xs) ⟨
118
+ fromList xs ∷ʳ x
119
+ ∎
110
120
where open CastReasoning
111
121
112
122
@@ -149,7 +159,7 @@ example2b eq xs a ys = begin
149
159
(a ∷ xs) ʳ++ ys ≂⟨ unfold-ʳ++ (a ∷ xs) ys ⟩ -- index: suc m + n
150
160
reverse (a ∷ xs) ++ ys ≂⟨ cong (_++ ys) (reverse-∷ a xs) ⟩ -- index: suc m + n
151
161
(reverse xs ∷ʳ a) ++ ys ≈⟨ ∷ʳ-++ eq a (reverse xs) ⟩ -- index: suc m + n
152
- reverse xs ++ (a ∷ ys) ≂⟨ unfold-ʳ++ xs (a ∷ ys) ⟨ -- index: m + suc n
162
+ reverse xs ++ (a ∷ ys) ≂⟨ unfold-ʳ++ xs (a ∷ ys) ⟨ -- index: m + suc n
153
163
xs ʳ++ (a ∷ ys) ∎ -- index: m + suc n
154
164
where open CastReasoning
155
165
@@ -169,29 +179,35 @@ example2b eq xs a ys = begin
169
179
-- Note. Technically, `A` and `B` should be vectors of different length
170
180
-- and that `ys`, `zs` are vectors of non-definitionally equal index.
171
181
example3a-fromList-++-++ : {xs ys zs : List A} →
172
- .(eq : L .length (xs L .++ ys L .++ zs) ≡
173
- L .length xs + (L .length ys + L .length zs)) →
174
- cast eq (fromList (xs L .++ ys L .++ zs)) ≡
182
+ .(eq : List .length (xs List .++ ys List .++ zs) ≡
183
+ List .length xs + (List .length ys + List .length zs)) →
184
+ cast eq (fromList (xs List .++ ys List .++ zs)) ≡
175
185
fromList xs ++ fromList ys ++ fromList zs
176
186
example3a-fromList-++-++ {xs = xs} {ys} {zs} eq = begin
177
- fromList (xs L.++ ys L.++ zs) ≈⟨ fromList-++ xs ⟩
178
- fromList xs ++ fromList (ys L.++ zs) ≈⟨ ≈-cong (fromList xs ++_) (cast-++ʳ (Lₚ.length-++ ys) (fromList xs))
179
- (fromList-++ ys) ⟩
180
- fromList xs ++ fromList ys ++ fromList zs ∎
187
+ fromList (xs List.++ ys List.++ zs)
188
+ ≈⟨ fromList-++ xs ⟩
189
+ fromList xs ++ fromList (ys List.++ zs)
190
+ ≈⟨ ≈-cong (fromList xs ++_) (cast-++ʳ (List.length-++ ys) (fromList xs)) (fromList-++ ys) ⟩
191
+ fromList xs ++ fromList ys ++ fromList zs
192
+ ∎
181
193
where open CastReasoning
182
194
183
195
-- As an alternative, one can manually apply `cast-++ʳ` to expose `cast`
184
196
-- in the subterm. However, this unavoidably duplicates the proof term.
185
197
example3b-fromList-++-++′ : {xs ys zs : List A} →
186
- .(eq : L .length (xs L .++ ys L .++ zs) ≡
187
- L .length xs + (L .length ys + L .length zs)) →
188
- cast eq (fromList (xs L .++ ys L .++ zs)) ≡
198
+ .(eq : List .length (xs List .++ ys List .++ zs) ≡
199
+ List .length xs + (List .length ys + List .length zs)) →
200
+ cast eq (fromList (xs List .++ ys List .++ zs)) ≡
189
201
fromList xs ++ fromList ys ++ fromList zs
190
202
example3b-fromList-++-++′ {xs = xs} {ys} {zs} eq = begin
191
- fromList (xs L.++ ys L.++ zs) ≈⟨ fromList-++ xs ⟩
192
- fromList xs ++ fromList (ys L.++ zs) ≈⟨ cast-++ʳ (Lₚ.length-++ ys) (fromList xs) ⟩
193
- fromList xs ++ cast _ (fromList (ys L.++ zs)) ≂⟨ cong (fromList xs ++_) (fromList-++ ys) ⟩
194
- fromList xs ++ fromList ys ++ fromList zs ∎
203
+ fromList (xs List.++ ys List.++ zs)
204
+ ≈⟨ fromList-++ xs ⟩
205
+ fromList xs ++ fromList (ys List.++ zs)
206
+ ≈⟨ cast-++ʳ (List.length-++ ys) (fromList xs) ⟩
207
+ fromList xs ++ cast _ (fromList (ys List.++ zs))
208
+ ≂⟨ cong (fromList xs ++_) (fromList-++ ys) ⟩
209
+ fromList xs ++ fromList ys ++ fromList zs
210
+ ∎
195
211
where open CastReasoning
196
212
197
213
-- `≈-cong` can be chained together much like how `cong` can be nested.
@@ -201,12 +217,16 @@ example3b-fromList-++-++′ {xs = xs} {ys} {zs} eq = begin
201
217
example4-cong² : ∀ .(eq : (m + 1 ) + n ≡ n + suc m) a (xs : Vec A m) ys →
202
218
cast eq (reverse ((xs ++ [ a ]) ++ ys)) ≡ ys ʳ++ reverse (xs ∷ʳ a)
203
219
example4-cong² {m = m} {n} eq a xs ys = begin
204
- reverse ((xs ++ [ a ]) ++ ys) ≈⟨ ≈-cong reverse (cast-reverse (cong (_+ n) (+-comm 1 m)) ((xs ∷ʳ a) ++ ys))
220
+ reverse ((xs ++ [ a ]) ++ ys)
221
+ ≈⟨ ≈-cong reverse (cast-reverse (cong (_+ n) (+-comm 1 m)) ((xs ∷ʳ a) ++ ys))
205
222
(≈-cong (_++ ys) (cast-++ˡ (+-comm 1 m) (xs ∷ʳ a))
206
223
(unfold-∷ʳ _ a xs)) ⟨
207
- reverse ((xs ∷ʳ a) ++ ys) ≈⟨ reverse-++ (+-comm (suc m) n) (xs ∷ʳ a) ys ⟩
208
- reverse ys ++ reverse (xs ∷ʳ a) ≂⟨ unfold-ʳ++ ys (reverse (xs ∷ʳ a)) ⟨
209
- ys ʳ++ reverse (xs ∷ʳ a) ∎
224
+ reverse ((xs ∷ʳ a) ++ ys)
225
+ ≈⟨ reverse-++ (+-comm (suc m) n) (xs ∷ʳ a) ys ⟩
226
+ reverse ys ++ reverse (xs ∷ʳ a)
227
+ ≂⟨ unfold-ʳ++ ys (reverse (xs ∷ʳ a)) ⟨
228
+ ys ʳ++ reverse (xs ∷ʳ a)
229
+ ∎
210
230
where open CastReasoning
211
231
212
232
------------------------------------------------------------------------
@@ -222,25 +242,33 @@ example4-cong² {m = m} {n} eq a xs ys = begin
222
242
-- reasoning system of `_≈[_]_` and switches back to the reasoning
223
243
-- system of `_≡_`.
224
244
example5-fromList-++-++′ : {xs ys zs : List A} →
225
- .(eq : L .length (xs L .++ ys L .++ zs) ≡
226
- L .length xs + (L .length ys + L .length zs)) →
227
- cast eq (fromList (xs L .++ ys L .++ zs)) ≡
245
+ .(eq : List .length (xs List .++ ys List .++ zs) ≡
246
+ List .length xs + (List .length ys + List .length zs)) →
247
+ cast eq (fromList (xs List .++ ys List .++ zs)) ≡
228
248
fromList xs ++ fromList ys ++ fromList zs
229
249
example5-fromList-++-++′ {xs = xs} {ys} {zs} eq = begin
230
- fromList (xs L.++ ys L.++ zs) ≈⟨ fromList-++ xs ⟩
231
- fromList xs ++ fromList (ys L.++ zs) ≃⟨ cast-++ʳ (Lₚ.length-++ ys) (fromList xs) ⟩
232
- fromList xs ++ cast _ (fromList (ys L.++ zs)) ≡⟨ cong (fromList xs ++_) (fromList-++ ys) ⟩
233
- fromList xs ++ fromList ys ++ fromList zs ≡-∎
250
+ fromList (xs List.++ ys List.++ zs)
251
+ ≈⟨ fromList-++ xs ⟩
252
+ fromList xs ++ fromList (ys List.++ zs)
253
+ ≃⟨ cast-++ʳ (List.length-++ ys) (fromList xs) ⟩
254
+ fromList xs ++ cast _ (fromList (ys List.++ zs))
255
+ ≡⟨ cong (fromList xs ++_) (fromList-++ ys) ⟩
256
+ fromList xs ++ fromList ys ++ fromList zs
257
+ ≡-∎
234
258
where open CastReasoning
235
259
236
260
-- Of course, it is possible to start with the reasoning system of `_≡_`
237
261
-- and then switch to the reasoning system of `_≈[_]_`.
238
262
example6a-reverse-∷ʳ : ∀ x (xs : Vec A n) → reverse (xs ∷ʳ x) ≡ x ∷ reverse xs
239
263
example6a-reverse-∷ʳ {n = n} x xs = begin-≡
240
- reverse (xs ∷ʳ x) ≡⟨ ≈-reflexive refl ⟨
241
- reverse (xs ∷ʳ x) ≈⟨ ≈-cong reverse (cast-reverse _ _) (unfold-∷ʳ (+-comm 1 n) x xs) ⟩
242
- reverse (xs ++ [ x ]) ≈⟨ reverse-++ (+-comm n 1 ) xs [ x ] ⟩
243
- x ∷ reverse xs ∎
264
+ reverse (xs ∷ʳ x)
265
+ ≡⟨ ≈-reflexive refl ⟨
266
+ reverse (xs ∷ʳ x)
267
+ ≈⟨ ≈-cong reverse (cast-reverse _ _) (unfold-∷ʳ (+-comm 1 n) x xs) ⟩
268
+ reverse (xs ++ [ x ])
269
+ ≈⟨ reverse-++ (+-comm n 1 ) xs [ x ] ⟩
270
+ x ∷ reverse xs
271
+ ∎
244
272
where open CastReasoning
245
273
246
274
example6b-reverse-∷ʳ-by-induction : ∀ x (xs : Vec A n) → reverse (xs ∷ʳ x) ≡ x ∷ reverse xs
0 commit comments