1 import Base
2 import ./list.bend as List
3
4 # queue.bend: a FIFO queue as two lists, specified by the list it holds.
5 #
6 # import ./queue.bend as Q
7 #
8 # push conses onto rear; pop takes from front, and when front is empty the
9 # reversed rear becomes the new front. Queue is linear (Type), so each
10 # queue value is used once; then each element is reversed at most once and
11 # every operation costs O(1) on average.
12 #
13 # model(q) is the list q holds. push_model and pop_model state push and
14 # pop in terms of it.
15
16 type Queue<-A: Data> is Type:
17 Queue{front: List<&2, A>, rear: List<&2, A>}
18
19 def empty(-A: Data) -> Queue:
20 Queue{Nil{}, Nil{}}
21
22 def model(-A: Data, q: Queue) -> List<&2, A>:
23 match q:
24 case Queue{f, r}:
25 List.append(&2, A, f, List.reverse(&2, A, r))
26
27 def push(-A: Data, q: Queue, x: A) -> Queue:
28 match q:
29 case Queue{f, r}:
30 Queue{f, x <> r}
31
32 # front is empty; f is the reversed rear
33 def pop.rot(-A: Data, f: List<&2, A>) -> List.Step<&1, A, Queue>:
34 match f:
35 case Nil{}:
36 List.Stop{}
37 case h <> t:
38 List.Next{h, Queue{t, Nil{}}}
39
40 def pop(-A: Data, q: Queue) -> List.Step<&1, A, Queue>:
41 match q:
42 case Queue{Nil{}, r}:
43 pop.rot(A, List.reverse(&2, A, r))
44 case Queue{h <> t, r}:
45 List.Next{h, Queue{t, r}}
46
47 # pop's result with the remaining queue replaced by its model
48 def pop.model(-A: Data, s: List.Step<&1, A, Queue>) -> List.Step<&2, A, List<&2, A>>:
49 match s:
50 case List.Stop{}:
51 List.Stop{}
52 case List.Next{x, q}:
53 List.Next{x, model(A, q)}
54
55 # push appends x to the model.
56 law push_model:
57 for -A: Data
58 for q: Queue
59 for +x: A
60 {List.append(&2, A, model(A, q), [x]) == model(A, push(A, q, x)) : List<&2, A>}
61
62 def push_model(A, q, x):
63 match q:
64 case Queue{+f, +r}:
65 %List.reverse_go(A, r, [x]) : {List.append(&2, A, List.append(&2, A, f, List.reverse(&2, A, r)), [x]) == List.append(&2, A, f, _) : List<&2, A>}
66 Equal.sym(List<&2, A>,
67 List.append(&2, A, f, List.append(&2, A, List.reverse(&2, A, r), [x])),
68 List.append(&2, A, List.append(&2, A, f, List.reverse(&2, A, r)), [x]),
69 List.append_assoc(A, f, List.reverse(&2, A, r), [x]))
70
71 law pop_model.rot:
72 for -A: Data
73 for f: List<&2, A>
74 {List.uncons(A, f) == pop.model(A, pop.rot(A, f)) : List.Step<&2, A, List<&2, A>>}
75
76 def pop_model.rot(A, f):
77 match f:
78 case Nil{}:
79 {==}
80 case h <> t:
81 %List.append_nil(A, t) : {List.Next{h, t} == List.Next{h, _} : List.Step<&2, A, List<&2, A>>}
82 {==}
83
84 # pop returns the model's head and tail.
85 law pop_model:
86 for -A: Data
87 for q: Queue
88 {List.uncons(A, model(A, q)) == pop.model(A, pop(A, q)) : List.Step<&2, A, List<&2, A>>}
89
90 def pop_model(A, q):
91 match q:
92 case Queue{Nil{}, r}:
93 pop_model.rot(A, List.reverse(&2, A, r))
94 case Queue{h <> t, r}:
95 {==}