2 (** Random Access Lists.
3 (Okasaki, "Purely Functional Data Structures", 10.1.2.)
5 The code below uses polymorphic recursion (both in the logic
8 Author: Jean-Christophe FilliĆ¢tre (CNRS)
11 module RandomAccessList
14 use int.ComputerDivision
23 | One 'a (ral ('a, 'a))
25 function flatten (l: list ('a, 'a)) : list 'a =
28 | Cons (x, y) l1 -> Cons x (Cons y (flatten l1))
31 let rec lemma length_flatten (l:list ('a, 'a))
32 ensures { length (flatten l) = 2 * length l }
36 | Cons (_,_) q -> length_flatten q
40 function elements (l: ral 'a) : list 'a =
43 | Zero l1 -> flatten (elements l1)
44 | One x l1 -> Cons x (flatten (elements l1))
47 let rec size (l: ral 'a) : int
49 ensures { result = length (elements l) }
53 | Zero l1 -> 2 * size l1
54 | One _ l1 -> 1 + 2 * size l1
57 let rec cons (x: 'a) (l: ral 'a) : ral 'a
59 ensures { elements result = Cons x (elements l) }
62 | Empty -> One x Empty
64 | One y l1 -> Zero (cons (x, y) l1)
67 let rec lemma nth_flatten (i: int) (l: list ('a, 'a))
68 requires { 0 <= i < length l }
70 ensures { match nth i l with
72 | Some (x0, x1) -> Some x0 = nth (2 * i) (flatten l) /\
73 Some x1 = nth (2 * i + 1) (flatten l) end }
77 | Cons _ r -> if i > 0 then nth_flatten (i-1) r
80 let rec lookup (i: int) (l: ral 'a) : 'a
81 requires { 0 <= i < length (elements l) }
83 ensures { nth i (elements l) = Some result }
87 | One x l1 -> if i = 0 then x else lookup (i-1) (Zero l1)
88 | Zero l1 -> let (x0, x1) = lookup (div i 2) l1 in
89 if mod i 2 = 0 then x0 else x1
92 let rec tail (l: ral 'a) : ral 'a
93 requires { elements l <> Nil }
95 ensures { match elements l with
97 | Cons _ l -> elements result = l
102 | One _ l1 -> Zero l1
103 | Zero l1 -> let (_, x1) = lookup 0 l1 in One x1 (tail l1)
106 let rec update (i: int) (y: 'a) (l: ral 'a) : ral 'a
107 requires { 0 <= i < length (elements l) }
109 ensures { nth i (elements result) = Some y}
110 ensures { forall j. 0 <= j < length (elements l) ->
111 j <> i -> nth j (elements result) = nth j (elements l) }
112 ensures { length (elements result) = length (elements l) }
113 ensures { match result, l with
114 | One _ _, One _ _ | Zero _, Zero _ -> true
120 | One x l1 -> if i = 0 then One y l1 else
121 match update (i-1) y (Zero l1) with
122 | Empty | One _ _ -> absurd
123 | Zero l1 -> One x l1
126 let (x0, x1) = lookup (div i 2) l1 in
128 update (div i 2) (if mod i 2 = 0 then (y,x1) else (x0,y)) l1 in
129 assert { forall j. 0 <= j < length (elements l) -> j <> i ->
130 match nth (div j 2) (elements l1) with
132 | Some (x0,_) -> Some x0 = nth (2 * (div j 2)) (elements l)
134 && nth j (elements l) = nth j (elements (Zero l1')) };
140 (** A straightforward encapsulation with a list ghost model
141 (in anticipation of module refinement) *)
152 type t 'a = { r: ral 'a; ghost l: list 'a }
153 invariant { l = elements r }
155 let constant empty : t 'a = { r = Empty; l = Nil }
156 ensures { result.l = Nil }
158 let size (t: t 'a) : int
159 ensures { result = length t.l }
163 let cons (x: 'a) (s: t 'a) : t 'a
164 ensures { result.l = Cons x s.l }
166 { r = cons x s.r; l = Cons x s.l }
168 let lookup (i: int) (s: t 'a) : 'a
169 requires { 0 <= i < length s.l }
170 ensures { Some result = nth i s.l }
176 (** Model using sequences instead of lists *)
178 module RandomAccessListWithSeq
181 use int.ComputerDivision
186 | Zero (ral ('a, 'a))
187 | One 'a (ral ('a, 'a))
189 function flatten (s: seq ('a, 'a)) : seq 'a =
190 create (2 * length s)
191 (fun i -> let (x0, x1) = s[div i 2] in
192 if mod i 2 = 0 then x0 else x1)
194 lemma cons_flatten : forall x y :'a,s:seq ('a,'a).
195 let a = flatten (cons (x,y) s) in
196 let b = cons x (cons y (flatten s)) in
197 a = b by a == b by forall i. 0 <= i < a.length -> a[i] = b[i]
198 by (i <= 1 so (cons (x,y) s)[div i 2] = (x,y))
199 \/ (i >= 2 so (cons (x,y) s)[div i 2] = s[div (i-2) 2]
202 function elements (l: ral 'a) : seq 'a =
205 | Zero l1 -> flatten (elements l1)
206 | One x l1 -> cons x (flatten (elements l1))
209 let rec size (l: ral 'a) : int
211 ensures { result = length (elements l) }
215 | Zero l1 -> 2 * size l1
216 | One _ l1 -> 1 + 2 * size l1
219 let rec cons (x: 'a) (l: ral 'a) : ral 'a
221 ensures { elements result == cons x (elements l) }
224 | Empty -> One x Empty
225 | Zero l1 -> One x l1
226 | One y l1 -> Zero (cons (x, y) l1)
229 let rec lookup (i: int) (l: ral 'a) : 'a
230 requires { 0 <= i < length (elements l) }
232 ensures { (elements l)[i] = result }
236 | One x l1 -> if i = 0 then x else lookup (i-1) (Zero l1)
237 | Zero l1 -> let (x0, x1) = lookup (div i 2) l1 in
238 if mod i 2 = 0 then x0 else x1
241 let rec tail (l: ral 'a) : ral 'a
242 requires { 0 < length (elements l) }
244 ensures { elements result == (elements l)[1..] }
248 | One _ l1 -> Zero l1
249 | Zero l1 -> let (_, x1) as p = lookup 0 l1 in
251 assert { elements l1 == cons p (elements tl) };
255 (** update in O(log n)
256 for this, we need to pass a function that will update the element
259 function setf (s: seq 'a) (i: int) (f: 'a -> 'a) : seq 'a =
262 let function aux (i: int) (f: 'a -> 'a) : ('a, 'a) -> ('a, 'a) =
263 fun z -> let (x,y) = z in if mod i 2 = 0 then (f x, y) else (x, f y)
265 let rec fupdate (f: 'a -> 'a) (i: int) (l: ral 'a) : ral 'a
266 requires { 0 <= i < length (elements l) }
268 ensures { elements result == setf (elements l) i f }
272 | One x l1 -> if i = 0 then One (f x) l1 else
273 cons x (fupdate f (i-1) (Zero l1))
275 let ul1 = fupdate (aux i f) (div i 2) l1 in
276 let res = Zero ul1 in
277 assert { forall j. 0 <= j < length (elements res) ->
278 (elements res)[j] = (setf (elements l) i f)[j]
279 by div j 2 <> div i 2 ->
280 (elements ul1)[div j 2] = (elements l1)[div j 2]
285 let function f (y: 'a) : 'a -> 'a = fun _ -> y
287 let update (i: int) (y: 'a) (l: ral 'a) : ral 'a
288 requires { 0 <= i < length (elements l) }
289 ensures { elements result == set (elements l) i y}