1
1
= Maps : Total and Partial Maps
2
2
3
3
> module Maps
4
+ >
4
5
5
6
Maps (or dictionaries) are ubiquitous data structures both generally and in the
6
7
theory of programming languages in particular; we're going to need them in many
@@ -52,9 +53,10 @@ equality comparison function for \idr{Id} and its fundamental property.
52
53
53
54
> data Id : Type where
54
55
> MkId : String -> Id
55
-
56
+ >
56
57
> beq_id : (x1, x2 : Id) -> Bool
57
58
> beq_id (MkId n1) (MkId n2) = decAsBool $ decEq n1 n2
59
+ >
58
60
59
61
\ todo[inline]{Edit }
60
62
@@ -68,8 +70,9 @@ present purposes you can think of it as just a fancy \idr{Bool}.)
68
70
69
71
> beq_id_refl : (x : Id) -> True = beq_id x x
70
72
> beq_id_refl (MkId n) with (decEq n n)
71
- > beq_id_refl _ | Yes _ = Refl
73
+ > beq_id_refl _ | Yes _ = Refl
72
74
> beq_id_refl _ | No contra = absurd $ contra Refl
75
+ >
73
76
74
77
The following useful property of \ idr{beq_id} follows from an analogous lemma
75
78
about strings :
@@ -78,25 +81,33 @@ about strings:
78
81
79
82
> iff : {p,q : Type } -> Type
80
83
> iff {p} {q} = (p -> q, q -> p)
81
-
84
+ >
82
85
> syntax [p] " <->" [q] = iff {p} {q}
86
+ >
83
87
84
- \ todo[inline]{Somehow this doesn't work if put under \ idr{where } as usual}
88
+ \ todo[inline]{Remove when a release with
89
+ https : //github.com/idris-lang/Idris-dev/pull/3925 happens}
85
90
86
- > bto : (beq_id x y = True) -> x = y
87
- > bto {x= MkId n1} {y= MkId n2} prf with (decEq n1 n2)
88
- > bto Refl | (Yes eq) = cong {f= MkId } eq
89
- > bto prf | (No _ ) = absurd prf
90
- > bfro : (x = y) -> beq_id x y = True
91
- > bfro {x= MkId n1} {y= MkId n2} prf with (decEq n1 n2)
92
- > bfro _ | (Yes _ ) = Refl
93
- > bfro prf | (No contra) = absurd $ contra $ idInj prf
94
- > where
95
- > idInj : MkId x = MkId y -> x = y
96
- > idInj Refl = Refl
91
+ > Uninhabited (False = True ) where
92
+ > uninhabited Refl impossible
93
+ >
97
94
98
95
> beq_id_true_iff : (beq_id x y = True) <-> x = y
99
96
> beq_id_true_iff = (bto, bfro)
97
+ > where
98
+ > bto : (beq_id x y = True) -> x = y
99
+ > bto {x= MkId n1} {y= MkId n2} prf with (decEq n1 n2)
100
+ > bto Refl | Yes eq = cong {f= MkId } eq
101
+ > bto prf | No _ = absurd prf
102
+ >
103
+ > idInj : MkId x = MkId y -> x = y
104
+ > idInj Refl = Refl
105
+ >
106
+ > bfro : (x = y) -> beq_id x y = True
107
+ > bfro {x= MkId n1} {y= MkId n2} prf with (decEq n1 n2)
108
+ > bfro _ | Yes _ = Refl
109
+ > bfro prf | No contra = absurd $ contra $ idInj prf
110
+ >
100
111
101
112
Similarly :
102
113
@@ -106,17 +117,20 @@ for now}
106
117
> not_true_and_false : (b = False) -> Not (b = True)
107
118
> not_true_and_false {b= False } _ Refl impossible
108
119
> not_true_and_false {b= True } Refl _ impossible
120
+ >
109
121
> not_true_is_false : Not (b = True) -> b = False
110
122
> not_true_is_false {b= False } h = Refl
111
- > not_true_is_false {b= True } h = absurd $ h Refl
112
-
123
+ > not_true_is_false {b= True } h = absurd $ h Refl
124
+ >
113
125
> beq_id_false_iff : (beq_id x y = False) <-> Not (x = y)
114
126
> beq_id_false_iff = (to, fro)
115
- > where
116
- > to : (beq_id x y = False) -> Not (x = y)
117
- > to beqf = not_true_and_false beqf . bfro
118
- > fro : (Not (x = y)) -> beq_id x y = False
119
- > fro noteq = not_true_is_false $ noteq . bto
127
+ > where
128
+ > to : (beq_id x y = False) -> Not (x = y)
129
+ > to beqf = not_true_and_false beqf . (snd beq_id_true_iff)
130
+ >
131
+ > fro : (Not (x = y)) -> beq_id x y = False
132
+ > fro noteq = not_true_is_false $ noteq . (fst beq_id_true_iff)
133
+ >
120
134
121
135
122
136
== Total Maps
@@ -135,17 +149,19 @@ simplifies proofs that use maps.
135
149
We build partial maps in two steps. First, we define a type of _total maps_ that
136
150
return a default value when we look up a key that is not present in the map.
137
151
138
- > total_map : Type -> Type
139
- > total_map a = Id -> a
152
+ > TotalMap : Type -> Type
153
+ > TotalMap a = Id -> a
154
+ >
140
155
141
156
Intuitively , a total map over an element type \ idr{a} is just a function that
142
157
can be used to look up \ idr{Id }s, yielding \ idr{a}s.
143
158
144
159
The function \ idr{t_empty} yields an empty total map , given a default element;
145
160
this map always returns the default element when applied to any id .
146
161
147
- > t_empty : (v : a) -> total_map a
162
+ > t_empty : (v : a) -> TotalMap a
148
163
> t_empty v = \ _ => v
164
+ >
149
165
150
166
We can also write this as :
151
167
@@ -157,8 +173,9 @@ More interesting is the \idr{update} function, which (as before) takes a map
157
173
\ idr{m}, a key \ idr{x}, and a value \ idr{v} and returns a new map that takes
158
174
\ idr{x} to \ idr{v} and takes every other key to whatever \ idr{m} does.
159
175
160
- > t_update : (x : Id) -> (v : a) -> (m : total_map a) -> total_map a
176
+ > t_update : (x : Id) -> (v : a) -> (m : TotalMap a) -> TotalMap a
161
177
> t_update x v m = \ x' => if beq_id x x' then v else m x'
178
+ >
162
179
163
180
This definition is a nice example of higher- order programming : \idr{t_update}
164
181
takes a _function_ \ idr{m} and yields a new function \ idr{\ x' => ... } that
@@ -170,25 +187,27 @@ this:
170
187
171
188
\ todo[inline]{Seems like a wrong description in the book here}
172
189
173
- > examplemap : total_map Bool
190
+ > examplemap : TotalMap Bool
174
191
> examplemap = t_update (MkId " foo" ) False $
175
192
> t_update (MkId " bar" ) True $
176
193
> t_empty False
194
+ >
177
195
178
196
This completes the definition of total maps. Note that we don't need to define a
179
197
\ idr{find} operation because it is just function application!
180
198
181
199
> update_example1 : examplemap (MkId "baz") = False
182
200
> update_example1 = Refl
183
-
201
+ >
184
202
> update_example2 : examplemap (MkId "foo") = False
185
203
> update_example2 = Refl
186
-
204
+ >
187
205
> update_example3 : examplemap (MkId "quux") = False
188
206
> update_example3 = Refl
189
-
207
+ >
190
208
> update_example4 : examplemap (MkId "bar") = True
191
209
> update_example4 = Refl
210
+ >
192
211
193
212
To use maps in later chapters, we'll need several fundamental facts about how
194
213
they behave. Even if you don't work the following exercises, make sure you
@@ -202,6 +221,7 @@ First, the empty map returns its default element for all keys:
202
221
203
222
> t_apply_empty : t_empty v x = v
204
223
> t_apply_empty = ? t_apply_empty_rhs
224
+ >
205
225
206
226
$\ square$
207
227
@@ -214,6 +234,7 @@ then look up \idr{x} in the map resulting from the \idr{update}, we get back
214
234
215
235
> t_update_eq : (t_update x v m) x = v
216
236
> t_update_eq = ? t_update_eq_rhs
237
+ >
217
238
218
239
$\ square$
219
240
@@ -226,6 +247,7 @@ a _different_ key \idr{x2} in the resulting map, we get the same result that
226
247
227
248
> t_update_neq : Not (x1 = x2) -> (t_update x1 v m) x2 = m x2
228
249
> t_update_neq neq = ? t_update_neq_rhs
250
+ >
229
251
230
252
$\ square$
231
253
@@ -239,6 +261,7 @@ simpler map obtained by performing just the second \idr{update} on \idr{m}:
239
261
240
262
> t_update_shadow : t_update x v2 $ t_update x v1 m = t_update x v2 m
241
263
> t_update_shadow = ? t_update_shadow_rhs
264
+ >
242
265
243
266
$\ square$
244
267
@@ -258,9 +281,10 @@ following:
258
281
> data Reflect : Type -> Bool -> Type where
259
282
> ReflectT : (p : Type ) -> Reflect p True
260
283
> ReflectF : (p : Type ) -> (Not p) -> Reflect p False
261
-
284
+ >
262
285
> beq_idP : Reflect (x = y) (beq_id x y)
263
286
> beq_idP = ? beq_idP_rhs
287
+ >
264
288
265
289
$\ square$
266
290
@@ -279,6 +303,7 @@ the following theorem, which states that if we update a map to assign key
279
303
280
304
> t_update_same : t_update x (m x) m = m
281
305
> t_update_same = ? t_update_same_rhs
306
+ >
282
307
283
308
$\ square$
284
309
@@ -292,6 +317,7 @@ we do the updates.
292
317
> t_update_permute : Not (x2 = x1) -> t_update x1 v1 $ t_update x2 v2 m
293
318
> = t_update x2 v2 $ t_update x1 v1 m
294
319
> t_update_permute neq = ? t_update_permute_rhs
320
+ >
295
321
296
322
$\ square$
297
323
@@ -302,44 +328,45 @@ Finally, we define _partial maps_ on top of total maps. A partial map with
302
328
elements of type \ idr{a} is simply a total map with elements of type \ idr{Maybe
303
329
a} and default element \ idr{Nothing }.
304
330
305
- > partial_map : Type -> Type
306
- > partial_map a = total_map (Maybe a)
307
-
308
- > empty : partial_map a
331
+ > PartialMap : Type -> Type
332
+ > PartialMap a = TotalMap (Maybe a)
333
+ >
334
+ > empty : PartialMap a
309
335
> empty = t_empty Nothing
310
-
311
- > update : (x : Id) -> (v : a) -> (m : partial_map a) -> partial_map a
336
+ >
337
+ > update : (x : Id) -> (v : a) -> (m : PartialMap a) -> PartialMap a
312
338
> update x v m = t_update x (Just v) m
339
+ >
313
340
314
341
We now straightforwardly lift all of the basic lemmas about total maps to
315
342
partial maps.
316
343
317
344
> apply_empty : empty {a} x = Nothing {a}
318
345
> apply_empty = Refl
319
-
346
+ >
320
347
> update_eq : (update x v m) x = Just v
321
348
> update_eq {x} {v} {m} =
322
349
> rewrite t_update_eq {x} {v= Just v} {m} in
323
- > Refl
324
-
350
+ > Refl
351
+ >
325
352
> update_neq : Not (x2 = x1) -> (update x2 v m) x1 = m x1
326
353
> update_neq {x1} {x2} {v} {m} neq =
327
354
> rewrite t_update_neq neq {x1= x2} {x2= x1} {v= Just v} {m} in
328
- > Refl
329
-
355
+ > Refl
356
+ >
330
357
> update_shadow : update x v2 $ update x v1 m = update x v2 m
331
358
> update_shadow {x} {v1} {v2} {m} =
332
359
> rewrite t_update_shadow {x} {v1= Just v1} {v2= Just v2} {m} in
333
- > Refl
334
-
360
+ > Refl
361
+ >
335
362
> update_same : m x = Just v -> update x v m = m
336
- > update_same {x} {m} {v} prf =
363
+ > update_same {x} {m} prf =
337
364
> rewrite sym prf in
338
365
> rewrite t_update_same {x} {m} in
339
- > Refl
340
-
366
+ > Refl
367
+ >
341
368
> update_permute : Not (x2 = x1) -> update x1 v1 $ update x2 v2 m
342
369
> = update x2 v2 $ update x1 v1 m
343
- > update_permute {x1} {x2} { v1} {v2} {m} neq =
344
- > rewrite t_update_permute neq {x1} {x2} { v1= Just v1} {v2= Just v2} {m} in
345
- > Refl
370
+ > update_permute {v1} {v2} {m} neq =
371
+ > rewrite t_update_permute neq {v1= Just v1} {v2= Just v2} {m} in
372
+ > Refl
0 commit comments