-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathImperativeCheerios.v
511 lines (418 loc) · 15 KB
/
ImperativeCheerios.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
Require Import List Arith PArith ZArith Ascii Omega Integers.
Import ListNotations.
Set Implicit Arguments.
Module Type SM.
Parameter t : Type.
Parameter e : Type.
Parameter skip : t.
Parameter seq : t -> t -> t.
Parameter putElt : e -> t.
(* Parameter putByte : char.t -> t. *)
(* ghost! *)
Parameter denote : t -> list e.
Parameter denote_skip : denote skip = [].
Parameter denote_seq : forall m1 m2, denote (seq m1 m2) = denote m1 ++ denote m2.
Parameter denote_putElt : forall b, denote (putElt b) = [b].
(* Parameter denote_putByte : forall c, denote (putByte c) = char.denote c. *)
End SM.
Module sm : SM with Definition e := bool.
Definition t := list bool.
Definition e := bool.
Definition skip : t := [].
Definition seq : t -> t -> t := @app _.
Definition putElt : bool -> t := fun b => [b].
(* Definition putByte : char.t -> t := char.denote. *)
Definition denote : t -> list bool := fun x => x.
Lemma denote_skip : denote skip = [].
Proof. reflexivity. Qed.
Lemma denote_seq : forall m1 m2, denote (seq m1 m2) = denote m1 ++ denote m2.
Proof. reflexivity. Qed.
Lemma denote_putElt : forall b, denote (putElt b) = [b].
Proof. reflexivity. Qed.
(* Lemma denote_putByte : forall c, denote (putByte c) = char.denote c.
Proof. reflexivity. Qed. *)
End sm.
Hint Rewrite sm.denote_skip sm.denote_seq sm.denote_putElt (*sm.denote_putByte*) : serializer.
Extract Constant sm.t => "Sm.t".
Extract Constant sm.skip => "Sm.skip".
Extract Constant sm.seq => "Sm.seq".
Extract Constant sm.putElt => "Sm.putElt".
Extract Constant sm.denote => "(fun x -> failwith ""sm.denote"")".
Module sm_notations.
Delimit Scope sm_scope with sm.
Infix "++" := sm.seq : sm_scope.
Open Scope sm_scope.
End sm_notations.
Import sm_notations.
Inductive step_result S A :=
| Error
| Success (a : A)
| More (s : S).
Arguments Error {_} {_}.
Arguments Success {_} {_} _.
Arguments More {_} {_} _.
Module Type DM.
Parameter t : Type -> Type.
Parameter e : Type.
Parameter ret : forall {A}, A -> t A.
Parameter bind : forall {A B}, t A -> (A -> t B) -> t B.
Parameter getElt : t e.
(* Parameter getByte : t char.t. *)
Parameter fold : forall {S A}, (S -> e -> step_result S A) -> S -> t A.
(* ghost! *)
Parameter denote : forall {A}, t A -> list e -> option (A * list e).
Parameter denote_ret : forall A (a : A) l, denote (ret a) l = Some (a, l).
Parameter denote_bind : forall A B (m : t A) (f : A -> t B) l,
denote (bind m f) l = match denote m l with
| None => None
| Some (a, l) => denote (f a) l
end.
Parameter denote_getElt : forall l,
denote getElt l = match l with
| [] => None
| b :: l => Some (b, l)
end.
(*
Parameter denote_getByte : forall l,
denote getByte l =
match l with
| b1::b2::b3::b4::b5::b6::b7::b8::l =>
Some (char.undenote [b1; b2; b3; b4; b5; b6; b7; b8], l)
| _ => None
end. *)
Parameter denote_fold : forall S A (f : S -> e -> step_result S A) (s : S) l,
denote (fold f s) l = match l with
| [] => None
| b :: l => match f s b with
| Error => None
| Success a => Some (a, l)
| More s => denote (fold f s) l
end
end.
End DM.
Module dm : DM with Definition e := bool.
Definition t (A : Type) : Type := list bool -> option (A * list bool).
Definition e := bool.
Definition ret {A} (a : A) : t A := fun l => Some (a, l).
Definition bind {A B} (m : t A) (f : A -> t B) : t B :=
fun l => match m l with
| None => None
| Some (a, l) => f a l
end.
Definition getElt : t bool :=
fun l => match l with
| [] => None
| b :: l => Some (b, l)
end.
(*
Definition getByte : t char.t :=
fun l => match l with
| b1::b2::b3::b4::b5::b6::b7::b8::l =>
Some (char.undenote [b1; b2; b3; b4; b5; b6; b7; b8], l)
| _ => None
end. *)
Fixpoint fold {S A} (f : S -> bool -> step_result S A) (s : S) (l : list bool) :=
match l with
| [] => None
| b :: l => match f s b with
| Error => None
| Success a => Some (a, l)
| More s => fold f s l
end
end.
Definition denote {A} (m : t A) := m.
Lemma denote_ret : forall A (a : A) l, denote (ret a) l = Some (a, l).
Proof. reflexivity. Qed.
Lemma denote_bind : forall A B (m : t A) (f : A -> t B) l,
denote (bind m f) l = match denote m l with
| None => None
| Some (a, l) => denote (f a) l
end.
Proof. reflexivity. Qed.
Lemma denote_getElt : forall l,
denote getElt l = match l with
| [] => None
| b :: l => Some (b, l)
end.
Proof. reflexivity. Qed.
(*
Lemma denote_getByte : forall l,
denote getByte l =
match l with
| b1::b2::b3::b4::b5::b6::b7::b8::l =>
Some (char.undenote [b1; b2; b3; b4; b5; b6; b7; b8], l)
| _ => None
end.
Proof. reflexivity. Qed.*)
Lemma denote_fold : forall S A (f : S -> bool -> step_result S A) (s : S) l,
denote (fold f s) l = match l with
| [] => None
| b :: l => match f s b with
| Error => None
| Success a => Some (a, l)
| More s => denote (fold f s) l
end
end.
Proof. destruct l; auto. Qed.
End dm.
Hint Rewrite dm.denote_ret dm.denote_bind dm.denote_getElt dm.denote_fold
(* dm.denote_getByte *) : serializer.
Hint Rewrite app_assoc_reverse app_nil_l app_nil_r : serializer.
Hint Rewrite <- app_comm_cons : serializer.
Extract Constant dm.t "'a" => "'a Dm.t".
Extract Constant dm.ret => "Dm.ret".
Extract Constant dm.bind => "Dm.bind".
Extract Constant dm.getElt => "Dm.getElt".
Extract Constant dm.fold => "Dm.fold".
Extract Constant dm.denote => "(fun x -> failwith ""dm.denote"")".
Module dm_ext.
Import dm.
Definition fmap {A B} (f : A -> B) (x : t A) : t B :=
bind x (fun a => ret (f a)).
Definition sequence {A B} (df : t (A -> B)) (da : t A) : t B :=
bind df (fun f => (bind da (fun a => ret (f a)))).
End dm_ext.
Hint Unfold dm_ext.fmap dm_ext.sequence : serializer.
Module dm_notations.
Delimit Scope dm_scope with dm.
Notation "m >>= f" := (@dm.bind _ _ m f) (at level 42, left associativity) : dm_scope.
Notation "x <- c1 ;; c2" := (c1 >>= (fun x => c2))%dm
(at level 100, c1 at next level, right associativity) : dm_scope.
Notation "e1 ;; e2" := (_ <- e1 ;; e2)%dm
(at level 100, right associativity) : dm_scope.
Notation "f <$> x" := (@dm_ext.fmap _ _ f x) (at level 42, left associativity) : dm_scope.
Notation "f <*> x" := (@dm_ext.sequence _ _ f x) (at level 42, left associativity) : dm_scope.
Open Scope dm.
End dm_notations.
Import dm_notations.
Notation serializer_spec_ty s d :=
(forall a l, dm.denote d (sm.denote (s a) ++ l) = Some (a, l)).
Class serializer (A : Type) := Serializer {
serialize : A -> sm.t;
deserialize : dm.t A;
serializer_spec : serializer_spec_ty serialize deserialize
}.
Hint Rewrite @serializer_spec : serializer.
Section lift.
Context {A B C D : Type}.
Context {sA : serializer A}.
Context {sB : serializer B}.
Context {sC : serializer C}.
Context {sD : serializer D}.
Definition liftD1 {X} (f : D -> X) : dm.t X :=
f <$> deserialize.
Definition liftD2 {X} (f : C -> D -> X) : dm.t X :=
(f <$> deserialize) >>= liftD1.
Definition liftD3 {X} (f : B -> C -> D -> X) : dm.t X :=
(f <$> deserialize) >>= liftD2.
Definition liftD4 {X} (f : A -> B -> C -> D -> X) : dm.t X :=
(f <$> deserialize) >>= liftD3.
End lift.
Hint Unfold liftD1 liftD2 liftD3 liftD4 : serializer.
Instance BoolSerializer : serializer bool := @Serializer _ sm.putElt dm.getElt _.
- intros. autorewrite with serializer. reflexivity.
Defined.
Fixpoint positive_serialize (p : positive) : sm.t :=
match p with
| xI p => serialize true ++ serialize true ++ positive_serialize p
| xO p => serialize true ++ serialize false ++ positive_serialize p
| xH => serialize false
end.
Module positive_deserialize.
Inductive state :=
| Start (k : positive -> positive)
| OneMoreElt (k : positive -> positive).
Definition step (s : state) (b : bool) : step_result _ _ :=
match s with
| Start k => if b then More (OneMoreElt k) else Success (k xH)
| OneMoreElt k => More (Start (fun p => k ((if b then xI else xO) p)))
end.
Definition f : dm.t positive :=
dm.fold step (Start (fun x => x)).
End positive_deserialize.
Lemma spec_pos' :
forall p k l,
dm.denote (dm.fold positive_deserialize.step (positive_deserialize.Start k))
(sm.denote (positive_serialize p) ++ l) = Some (k p, l).
Proof.
induction p; simpl; intros.
- now autorewrite with serializer using (simpl; try rewrite IHp).
- now autorewrite with serializer using (simpl; try rewrite IHp).
- now autorewrite with serializer.
Qed.
Lemma spec_pos : serializer_spec_ty positive_serialize positive_deserialize.f.
Proof.
intros p l.
unfold positive_deserialize.f.
apply spec_pos'.
Qed.
Instance positive_serializer :
serializer positive := @Serializer _ positive_serialize positive_deserialize.f spec_pos.
Definition Z_serialize (z : Z) : sm.t :=
match z with
| Z0 => serialize false
| Zpos p => serialize true ++ serialize true ++ serialize p
| Zneg p => serialize true ++ serialize false ++ serialize p
end.
Definition Z_deserialize : dm.t Z :=
tag <- deserialize ;;
match tag with
| true => sign <- deserialize ;;
(match sign with true => Zpos | false => Zneg end) <$> deserialize
| false => dm.ret Z0
end.
Ltac serializer_spec_crush :=
intros; autounfold with serializer; autorewrite with serializer; auto.
Lemma Z_serializer_spec :
serializer_spec_ty Z_serialize Z_deserialize.
Proof.
unfold Z_serialize, Z_deserialize.
destruct a; serializer_spec_crush.
Qed.
Instance Z_serializer : serializer Z :=
{| serialize := Z_serialize;
deserialize := Z_deserialize;
serializer_spec := Z_serializer_spec
|}.
Definition N_serialize (n : N) :=
match n with
| N0 => serialize false
| Npos p => serialize true ++ serialize p
end.
Definition N_deserialize :=
tag <- deserialize ;;
match tag with
| false => dm.ret N0
| true => Npos <$> deserialize
end.
Lemma N_serializer_spec :
serializer_spec_ty N_serialize N_deserialize.
Proof.
unfold N_serialize, N_deserialize.
destruct a; serializer_spec_crush.
Qed.
Instance N_serializer : serializer N :=
{| serialize := N_serialize;
deserialize := N_deserialize;
serializer_spec := N_serializer_spec
|}.
Definition nat_serialize (n : nat) := serialize (N.of_nat n).
Definition nat_deserialize := N.to_nat <$> deserialize.
Lemma nat_serializer_spec :
serializer_spec_ty nat_serialize nat_deserialize.
Proof.
unfold nat_serialize, nat_deserialize.
serializer_spec_crush.
now rewrite Nnat.Nat2N.id.
Qed.
Instance nat_serializer : serializer nat :=
{| serialize := nat_serialize;
deserialize := nat_deserialize;
serializer_spec := nat_serializer_spec
|}.
Arguments Some {_} _.
Arguments cons {_} _ _.
Section combinators.
(* This section gives instances for various type constructors, including pairs
and lists. *)
Variables A B : Type.
Variable sA : serializer A.
Variable sB : serializer B.
Definition option_serialize (x : option A) :=
match x with
| Some a => serialize true ++ serialize a
| None => serialize false
end.
Definition option_deserialize : dm.t (option A) :=
b <- deserialize ;;
match b with
| true => Some <$> deserialize
| false => dm.ret None
end.
Lemma option_serializer_spec :
serializer_spec_ty option_serialize option_deserialize.
Proof.
unfold option_serialize, option_deserialize.
destruct a; serializer_spec_crush.
Qed.
Global Instance option_serializer : serializer (option A) :=
{| serialize := option_serialize;
deserialize := option_deserialize;
serializer_spec := option_serializer_spec
|}.
Definition pair_serialize (x : A * B) :=
let (a, b) := x in serialize a ++ serialize b.
Definition pair_deserialize : dm.t (A * B) :=
liftD2 pair.
Lemma pair_serializer_spec :
serializer_spec_ty pair_serialize pair_deserialize.
Proof.
unfold pair_serialize, pair_deserialize.
destruct a; serializer_spec_crush.
Qed.
Global Instance pair_serializer : serializer (A * B) :=
{| serialize := pair_serialize;
deserialize := pair_deserialize;
serializer_spec := pair_serializer_spec
|}.
Definition sum_serialize (x : A + B) :=
match x with
| inl a => serialize true ++ serialize a
| inr b => serialize false ++ serialize b
end.
Definition sum_deserialize : dm.t (A + B) :=
b <- deserialize ;;
match b with
| true => inl <$> deserialize
| false => inr <$> deserialize
end.
Lemma sum_serializer_spec :
serializer_spec_ty sum_serialize sum_deserialize.
Proof.
unfold sum_serialize, sum_deserialize.
destruct a; serializer_spec_crush.
Qed.
Global Instance sum_serializer : serializer (A + B) :=
{| serialize := sum_serialize;
deserialize := sum_deserialize;
serializer_spec := sum_serializer_spec
|}.
Fixpoint list_serialize_rec (l : list A) : sm.t :=
match l with
| [] => sm.skip
| a :: l' => serialize a ++ list_serialize_rec l'
end.
Definition list_serialize (l : list A) : sm.t :=
serialize (length l) ++ list_serialize_rec l.
Fixpoint list_deserialize_rec (n : nat) : dm.t (list A) :=
match n with
| 0 => dm.ret []
| S n' => cons <$> deserialize <*> list_deserialize_rec n'
end.
Definition list_deserialize : dm.t (list A) :=
deserialize >>= list_deserialize_rec.
Lemma list_serializer_spec_rec :
forall l bin, dm.denote (list_deserialize_rec (length l))
(sm.denote (list_serialize_rec l) ++ bin) = Some (l, bin).
Proof.
induction l; simpl; serializer_spec_crush.
rewrite IHl.
serializer_spec_crush.
Qed.
Lemma list_serializer_spec :
serializer_spec_ty list_serialize list_deserialize.
Proof.
unfold list_serialize, list_deserialize.
serializer_spec_crush.
apply list_serializer_spec_rec.
Qed.
Global Instance list_serializer : serializer (list A) :=
{| serialize := list_serialize;
deserialize := list_deserialize;
serializer_spec := list_serializer_spec
|}.
End combinators.
Require Import ExtrOcamlBasic.
Extraction Inline positive_serializer Z_serializer N_serializer nat_serializer option_serializer pair_serializer sum_serializer list_serializer.
Set Extraction Optimize.
Recursive Extraction list_serializer.