Source file decompress_q.ml
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
type 'a digit = Zero | One of 'a | Two of 'a * 'a | Three of 'a * 'a * 'a
type 'a t =
| Shallow of 'a digit
| Deep of int * 'a digit * ('a * 'a) t Lazy.t * 'a digit
let empty = Shallow Zero
let is_empty = function
| Shallow Zero -> true
| Shallow (One _ | Two _ | Three _) | Deep _ -> false
let _single x = Shallow (One x)
let _double x y = Shallow (Two (x, y))
let _three x y z = Shallow (Three (x, y, z))
let _deep n hd middle tl =
assert (hd <> Zero && tl <> Zero) ;
Deep (n, hd, middle, tl)
let _empty = Lazy.from_val empty
let rec cons : 'a. 'a -> 'a t -> 'a t =
fun x q ->
match q with
| Shallow Zero -> _single x
| Shallow (One y) -> _double x y
| Shallow (Two (y, z)) -> _three x y z
| Shallow (Three (y, z, z')) -> _deep 4 (Two (x, y)) _empty (Two (z, z'))
| Deep (_, Zero, _middle, _tl) -> assert false
| Deep (n, One y, _middle, _tl) -> _deep (n + 1) (Two (x, y)) _middle _tl
| Deep (n, Two (y, z), _middle, _tl) ->
_deep (n + 1) (Three (x, y, z)) _middle _tl
| Deep (n, Three (y, z, z'), (lazy _middle), _tl) ->
_deep (n + 1) (Two (x, y)) (lazy (cons (z, z') _middle)) _tl
exception Empty
let rec take_front_exn : 'a. 'a t -> 'a * 'a t =
fun q ->
match q with
| Shallow Zero -> raise Empty
| Shallow (One x) -> x, empty
| Shallow (Two (x, y)) -> x, Shallow (One y)
| Shallow (Three (x, y, z)) -> x, Shallow (Two (y, z))
| Deep (_, Zero, _, _) -> assert false
| Deep (n, One x, (lazy _middle), _tail) ->
if is_empty _middle then x, Shallow _tail
else
let (y, z), _middle = take_front_exn _middle in
x, _deep (n - 1) (Two (y, z)) (Lazy.from_val _middle) _tail
| Deep (n, Two (x, y), _middle, _tail) ->
x, _deep (n - 1) (One y) _middle _tail
| Deep (n, Three (x, y, z), _middle, _tail) ->
x, _deep (n - 1) (Two (y, z)) _middle _tail
let take_front q = try Some (take_front_exn q) with Empty -> None
let add_seq_front seq q =
let l = ref [] in
seq (fun x -> l := x :: !l) ;
List.fold_left (fun q x -> cons x q) q !l
let of_seq seq = add_seq_front seq empty