Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
IFSeqObj.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 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
(******************************************************************************) (* *) (* Feat *) (* *) (* François Pottier, Inria Paris *) (* *) (* Copyright Inria. All rights reserved. This file is distributed under the *) (* terms of the MIT license, as described in the file LICENSE. *) (******************************************************************************) (* This is an implementation of implicit finite sequences as objects, that is, records of closures. This is the implementation style proposed in the Feat paper by Duregard et al. *) (* In this implementation, the constructors have time complexity O(1), under the assumption that the arithmetic operations provided by [Z] cost O(1) as well. *) module Make (Z : BigIntSig.BASIC) = struct type index = Z.t (* A sequence stores its length (which is computed at construction time) as well as [get] and [foreach] methods. *) (* The [foreach] method takes a Boolean sense as a parameter. This allows us to easily implement the [foreach] method of a reversed sequence, as produced by the [rev] combinator. *) (* For comments on [to_seq], see IFSeqSyn. *) type ('a, 'b) producer = ('a -> 'b Seq.t -> 'b Seq.t) -> 'b Seq.t -> 'b Seq.t type 'a seq = { length : index; get : index -> 'a; foreach: bool -> ('a -> unit) -> unit; to_seq : 'b . bool -> ('a, 'b) producer; } let is_empty s = Z.equal s.length Z.zero let out_of_bounds () = failwith "Index is out of bounds." let empty = let length = Z.zero and get _ = out_of_bounds() and foreach _sense _k = () and to_seq _sense _cons k = k in { length; get; foreach; to_seq } let zero = empty let singleton x = let length = Z.one and get i = if Z.equal i Z.zero then x else out_of_bounds() and foreach _sense k = k x and to_seq _sense cons k = cons x k in { length; get; foreach; to_seq } let one = singleton let rev s = let length = s.length and get i = s.get (Z.sub (Z.pred s.length) i) and foreach sense k = s.foreach (not sense) k and to_seq sense cons k = s.to_seq (not sense) cons k in { length; get; foreach; to_seq } let sum s1 s2 = let length = Z.add s1.length s2.length and get i = if Z.lt i s1.length then s1.get i else s2.get (Z.sub i s1.length) and foreach sense k = let s1, s2 = if sense then s1, s2 else s2, s1 in s1.foreach sense k; s2.foreach sense k and to_seq sense cons k = let s1, s2 = if sense then s1, s2 else s2, s1 in s1.to_seq sense cons (fun () -> s2.to_seq sense cons k ()) in { length; get; foreach; to_seq } let sum s1 s2 = (* To save space and reduce access time, we recognize an empty sequence as a neutral element for concatenation. *) if is_empty s1 then s2 else if is_empty s2 then s1 else sum s1 s2 let ( ++ ) = sum let product s1 s2 = let length = Z.mul s1.length s2.length and get i = let q, r = Z.div_rem i s2.length in s1.get q, s2.get r and foreach sense k = s1.foreach sense (fun x1 -> s2.foreach sense (fun x2 -> k (x1, x2) ) ) and to_seq sense cons k = s1.to_seq sense (fun x1 k -> s2.to_seq sense (fun x2 k -> cons (x1, x2) k ) k ) k in { length; get; foreach; to_seq } let product s1 s2 = (* To save space, we recognize an empty sequence as an absorbing element for product. This also eliminates the risk of a division by zero in the above code, which could arise if the user attempts an out-of-bounds access. *) if is_empty s1 || is_empty s2 then empty else product s1 s2 let ( ** ) = product let map phi s = let length = s.length and get i = phi (s.get i) and foreach sense k = s.foreach sense (fun x -> k (phi x)) and to_seq sense cons k = s.to_seq sense (fun x k -> cons (phi x) k) k in { length; get; foreach; to_seq } let map phi s = (* To save space, we recognize an empty sequence as a fixed point for map. *) if is_empty s then empty else map phi s let rec interval sense a b : (int, 'b) producer = fun cons k -> if a < b then (* Compute the first element [x] and the parameters [a] and [b] of the recursive call. *) let x, a, b = if sense then a, a+1, b else b-1, a, b-1 in (* Produce [x] and delay the recursive call. *) cons x (fun () -> interval sense a b cons k ()) else k let up a b = if a < b then let length = Z.of_int (b - a) and get i = match Z.to_int i with | exception Z.Overflow -> out_of_bounds() | i -> let x = a + i in if x < a || b <= x then out_of_bounds() else x and foreach sense k = if sense then for x = a to b - 1 do k x done else for x = b - 1 downto a do k x done and to_seq sense cons k = interval sense a b cons k in { length; get; foreach; to_seq } else empty let length s = s.length let get s i = s.get i let foreach s k = s.foreach true k let cons x xs = fun () -> Seq.Cons (x, xs) let to_seq s k = s.to_seq true cons k end