0 | ||| Fin-based vects encode not just their current size but also their
  1 | ||| largest size. See also Data.FVect.Capacity for a view that is
  2 | ||| useful when determining if you want to add to an FVect depending
  3 | ||| on whether or not it is full.
  4 | module Data.FVect
  5 |
  6 | import Data.Vect
  7 | import public Data.Fin
  8 | import Data.Nat
  9 | import Decidable.Equality
 10 |
 11 | %hide Prelude.Types.elem
 12 |
 13 | %default total
 14 |
 15 | ||| A Fin-based Vect. Can be thought of as a Vect with both a length
 16 | ||| and a maximum capacity. Operations like filtering can reduce the
 17 | ||| length without affecting maximum capacity which provides proof
 18 | ||| that a Vect's length has not increased over the course of a series
 19 | ||| of operations.
 20 | public export
 21 | data FVect : (capacity : Nat) -> (len : Fin (S capacity)) -> (elem : Type) -> Type where
 22 |   Nil : FVect capacity FZ elem
 23 |
 24 |   ||| Cons an element to the FVect, increasing its capacity.
 25 |   ||| See (:::) for an operator that conses an element without
 26 |   ||| increasing capacity.
 27 |   (::) : (x : elem)
 28 |       -> (xs : FVect capacity len elem)
 29 |       -> FVect (S capacity) (FS len) elem
 30 |
 31 | %name FVect xs, ys, zs
 32 |
 33 | Uninhabited (FVect 0 (FS l) e) where
 34 |   uninhabited [] impossible
 35 |   uninhabited (x :: xs) impossible
 36 |
 37 | ||| Cons an element without increasing the capacity of the FVect. You
 38 | ||| must make sure the capacity and length of the FVect being consed
 39 | ||| onto are accessible in the context where you call this.
 40 | |||
 41 | ||| The function signature is a bit tricky because it needs to ensure
 42 | ||| you are going from length of type Fin n to length of type Fin n
 43 | ||| but calling Fin's FS constructor increments n. To increment the
 44 | ||| value stored without weakening the bounds of the Fin, we go from
 45 | ||| (weaken (Fin (S n))) to (FS (Fin (S n))).
 46 | |||
 47 | ||| In other words, we go from a weaker input Fin to the succesor of a
 48 | ||| stronger bounded Fin.
 49 | public export
 50 | consWeaker : {n : Nat}
 51 |           -> {len' : Fin (S n)}
 52 |           -> (v : elem)
 53 |           -> FVect (S n) (weaken len') elem
 54 |           -> FVect (S n) (FS len') elem
 55 | consWeaker {n = n}     {len' = FZ}      v _ = [v]
 56 | consWeaker {n = 0}     {len' = (FS l')} _ _ = absurd l'
 57 | consWeaker {n = (S k)} {len' = (FS l')} v (x :: xs) = v :: (x
 58 |            `consWeaker` xs)
 59 |
 60 | public export
 61 | strengthenLT : {0 n : _}
 62 |             -> (j : Fin (S n))
 63 |             -> (0 prf : (finToNat j) `LT` n) =>
 64 |                Fin n
 65 | strengthenLT FZ @{(LTESucc _)} = FZ
 66 | strengthenLT (FS x) @{(LTESucc _)} = FS (strengthenLT x)
 67 |
 68 | weakenStrengthenCancel : {0 n : _}
 69 |                       -> (x : Fin (S n))
 70 |                       -> (0 prf : (finToNat x) `LT` n) =>
 71 |                          (weaken (strengthenLT x)) = x
 72 | weakenStrengthenCancel FZ @{(LTESucc y)} = Refl
 73 | weakenStrengthenCancel (FS x) @{(LTESucc y)} =
 74 |   cong FS (weakenStrengthenCancel x)
 75 |
 76 | ||| Like `consWeaker`, cons an element onto an FVect without changing
 77 | ||| its capacity.
 78 | |||
 79 | ||| You need only know that the existing FVect is not at capacity to
 80 | ||| know that an element can be consed onto it without increasing the
 81 | ||| capacity.
 82 | public export
 83 | consLT : {n : Nat}
 84 |       -> {len : Fin (S (S n))}
 85 |       -> (0 ltPrf : (finToNat len) `LT` (S n)) =>
 86 |          (v : elem)
 87 |       -> FVect (S n) len elem
 88 |       -> FVect (S n) (FS (strengthenLT len)) elem
 89 | consLT v xs with (weakenStrengthenCancel len)
 90 |   consLT v xs | cancelPrf = v `consWeaker` (rewrite cancelPrf in xs)
 91 |
 92 | ||| Like `consWeaker`, cons an element onto an FVect without changing
 93 | ||| its capacity.
 94 | |||
 95 | ||| You need only know that the existing FVect is not at capacity to
 96 | ||| know that an element can be consed onto it without increasing the
 97 | ||| capacity.
 98 | public export
 99 | (:::) : {n : Nat}
100 |      -> {len : Fin (S (S n))}
101 |      -> (0 ltPrf : (finToNat len) `LT` (S n)) =>
102 |         (v : elem)
103 |      -> FVect (S n) len elem
104 |      -> FVect (S n) (FS (strengthenLT len)) elem
105 | (:::) = consLT
106 |
107 |
108 | ||| Create an empty FVect with the given capacity.
109 | export
110 | empty : (capacity : Nat) -> FVect capacity FZ elem
111 | empty _ = []
112 |
113 | ||| Create an FVect by replicating the given element enough to fill
114 | ||| the needed length.
115 | export
116 | replicate : {capacity : Nat}
117 |          -> (l : Fin (S capacity))
118 |          -> elem
119 |          -> FVect capacity l elem
120 | replicate {capacity} FZ x = []
121 | replicate {capacity = (S k)} (FS y) x = x :: replicate y x
122 |
123 | ||| Allow FVect to hold one more element.
124 | ||| Do not change the elements currently in the FVect.
125 | public export
126 | addCapacity : FVect c l a -> (FVect (S c) (weaken l) a)
127 | addCapacity [] = []
128 | addCapacity (x :: xs) = x :: (addCapacity xs)
129 |
130 | ||| Allow FVect to hold n more elements.
131 | ||| Do not change the elements currently in the FVect.
132 | public export
133 | addCapacityN : (n : Nat)
134 |             -> FVect capacity l a
135 |             -> (FVect (capacity + n) (weakenN n l) a)
136 | addCapacityN n [] = Nil
137 | addCapacityN n (x :: xs) = x :: (addCapacityN n xs)
138 |
139 | ||| Reduce the FVect's capacity to hold elements.
140 | public export
141 | removeCapacity : {n : Nat}
142 |               -> {len' : Fin (S n)}
143 |               -> FVect (S n) (weaken len') a
144 |               -> FVect n len' a
145 | removeCapacity {n = n}     {len' = FZ}      [] = []
146 | removeCapacity {n = 0}     {len' = (FS l')} (x :: xs) = absurd l'
147 | removeCapacity {n = (S k)} {len' = (FS l')} (x :: xs) =
148 |   x :: (removeCapacity xs)
149 |
150 | ||| Calculate the length of the FVect.
151 | export
152 | length : FVect capacity l a
153 |       -> Nat
154 | length [] = 0
155 | length (x :: xs) = S (length xs)
156 |
157 | --
158 | -- to/from List and Vect
159 | --
160 |
161 | ||| Get the smallest FVect that can contain the given Vect.
162 | export
163 | fromVect : Vect l a -> FVect l (last {n=l}) a
164 | fromVect [] = []
165 | fromVect (x :: xs) = x :: fromVect xs
166 |
167 | export
168 | toVect : FVect c l elem -> Vect (finToNat l) elem
169 | toVect [] = []
170 | toVect (x :: xs) = x :: (toVect xs)
171 |
172 | -- toList provided by Foldable/Data.List
173 |
174 | --
175 | -- Accessors
176 | --
177 |
178 | ||| All but the first element of the FVect.
179 | ||| This operation does not change capacity. This means you can carry
180 | ||| out this operation and retain proof that the new FVect length is
181 | ||| less than or equal to the original FVect (although in this case
182 | ||| the length is exactly one less than before the call to tail).
183 | public export
184 | tail : FVect c (FS l) elem -> FVect c (weaken l) elem
185 | tail (x :: xs) = addCapacity xs
186 |
187 | ||| Like tail but reduces the capacity by 1 in addition
188 | ||| to dropping the first element.
189 | public export
190 | dropFirst : FVect (S c) (FS l) elem -> FVect c l elem
191 | dropFirst (x :: xs) = xs
192 |
193 | public export
194 | head : FVect c (FS l) elem -> elem
195 | head (x :: _) = x
196 |
197 | public export
198 | last : FVect c (FS l) elem -> elem
199 | last [x] = x
200 | last (x :: (y :: xs)) = last $ y :: xs
201 |
202 | ||| All but the last element of the FVect.
203 | ||| This operation does not change capacity. This means you can carry
204 | ||| out this operation and retain proof that the new FVect length is
205 | ||| less than or equal to the original FVect (although in this case
206 | ||| the length is exactly one less than before the call to tail).
207 | public export
208 | init : FVect c (FS l) elem -> FVect c (weaken l) elem
209 | init [_] = []
210 | init (x :: (y :: xs)) = x :: (init $ y :: xs)
211 |
212 | ||| Like init but reduces the capacity by 1 in addition to removing
213 | ||| the last element.
214 | public export
215 | dropLast : FVect (S c) (FS l) elem -> FVect c l elem
216 | dropLast [_] = []
217 | dropLast (x :: (y :: xs)) = x :: (dropLast $ y :: xs)
218 |
219 | --
220 | -- Properties
221 | --
222 |
223 | ||| If two FVects are equal, their heads and tails are equal.
224 | export
225 | fVectInjective : {0 xs : FVect c l elem}
226 |               -> {0 ys : FVect c l elem}
227 |               -> x :: xs = y :: ys
228 |               -> (x = y, xs = ys)
229 | fVectInjective Refl = (Refl, Refl)
230 |
231 | ||| If you add and then remove capacity, you are left with the
232 | ||| original capacity.
233 | ||| In fact, you are left with exactly the original FVect.
234 | export
235 | addRemoveCapacityInverse : (xs : FVect c l elem)
236 |                         -> (removeCapacity (addCapacity xs)) = xs
237 | addRemoveCapacityInverse [] = Refl
238 | addRemoveCapacityInverse (x :: xs) =
239 |   cong (x ::) (addRemoveCapacityInverse xs)
240 |
241 | ||| The calculated length of an FVect reifies the erased length of the
242 | ||| FVect.
243 | export
244 | lengthReifies : (v : FVect c l elem) -> length v = finToNat l
245 | lengthReifies [] = Refl
246 | lengthReifies (x :: xs) = cong S (lengthReifies xs)
247 |
248 | --
249 | -- Functor
250 | --
251 |
252 | export
253 | Functor (FVect c l) where
254 |   map f [] = []
255 |   map f (x :: xs) = f x :: map f xs
256 |
257 | --
258 | -- Applicative
259 | --
260 |
261 | export
262 | {capacity : Nat} -> {l : Fin (S capacity)} -> Applicative (FVect capacity l) where
263 |   pure = replicate _
264 |
265 |   [] <*> [] = []
266 |   (f :: fs) <*> (x :: xs) = f x :: (fs <*> xs)
267 |
268 | --
269 | -- Foldable
270 | --
271 |
272 | export
273 | Foldable (FVect c l) where
274 |   foldr _ acc [] = acc
275 |   foldr f acc (x :: xs) = f x $ foldr f acc xs
276 |
277 | --
278 | -- Eq/DecEq
279 | --
280 |
281 | export
282 | Eq elem => Eq (FVect c l elem) where
283 |   [] == [] = True
284 |   (x :: xs) == (y :: ys) = if x == y
285 |                               then xs == ys
286 |                               else False
287 |
288 | export
289 | DecEq elem => DecEq (FVect c l elem) where
290 |   decEq [] [] = Yes Refl
291 |   decEq (x :: xs) (y :: ys) with (decEq x y, decEq xs ys)
292 |     decEq (y :: ys) (y :: ys) | (Yes Refl, Yes Refl)  = Yes Refl
293 |     decEq (x :: xs) (y :: ys) | (_,        No contra) = No $ contra . snd . fVectInjective
294 |     decEq (x :: xs) (y :: ys) | (No contra, _)        = No $ contra . fst . fVectInjective
295 |
296 | --
297 | -- Utility
298 | --
299 |
300 | ||| Remove all Nothings from the FVect.
301 | ||| This operation does not change capacity. That means you can carry
302 | ||| out this operation and retain proof that the new FVect length is
303 | ||| less than or equal to that of the original FVect.
304 | export
305 | catMaybes : {len : Fin (S capacity)}
306 |          -> FVect capacity len (Maybe elem)
307 |          -> (len' : Fin (S capacity) ** FVect capacity len' elem)
308 | catMaybes {len = FZ} [] = (FZ ** [])
309 | catMaybes {len = (FS k)} (Nothing  :: xs) = let (l' ** rest= catMaybes xs in
310 |                                               (weaken l' ** addCapacity rest)
311 | catMaybes {len = (FS k)} ((Just x) :: xs) = let (l' ** rest= catMaybes xs in
312 |                                               (FS l' ** x :: rest)
313 |
314 | ||| Map all elements, removing any Nothings along the way.
315 | ||| This operation does not change capacity. That means you can carry
316 | ||| out this operation and retain proof that the new FVect length is
317 | ||| less than or equal to that of the original FVect.
318 | export
319 | mapMaybes : {len : Fin (S capacity)}
320 |          -> (f : elem -> Maybe elem')
321 |          -> FVect capacity len elem
322 |          -> (len' : Fin (S capacity) ** FVect capacity len' elem')
323 | mapMaybes {len = FZ} f [] = (FZ ** [])
324 | mapMaybes {len = (FS k)} f (x :: xs) = case (f x) of
325 |                                             Nothing => let (l' ** rest= mapMaybes f xs in
326 |                                                            (weaken l' ** addCapacity rest)
327 |                                             (Just y) => let (l' ** rest= mapMaybes f xs in
328 |                                                             (FS l' ** y :: rest)
329 |
330 | ||| Filter down to only elements matching the predicate.
331 | ||| This operation does not change capacity. That means you can carry
332 | ||| out this operation and retain proof that the new FVect length is
333 | ||| less than or equal to that of the original FVect.
334 | export
335 | filter : (elem -> Bool)
336 |       -> FVect capacity len elem
337 |       -> (len' : Fin (S capacity) ** FVect capacity len' elem)
338 | filter p [] = (FZ ** [])
339 | filter p (x :: xs) = let (l' ** rest= filter p xs in
340 |                          if p x
341 |                             then (FS l' ** x :: rest)
342 |                             else (weaken l' ** addCapacity rest)
343 |
344 |