0 | module Data.Vect.Quantifiers
  1 |
  2 | import Data.DPair
  3 | import Data.Vect
  4 | import Data.Vect.Elem
  5 |
  6 | import Decidable.Equality
  7 |
  8 | %default total
  9 |
 10 | ------------------------------------------------------------------------
 11 | -- Quantifier types
 12 |
 13 | namespace Any
 14 |
 15 |   ||| A proof that some element of a vector satisfies some property
 16 |   |||
 17 |   ||| @ p the property to be satsified
 18 |   public export
 19 |   data Any : (0 p : a -> Type) -> Vect n a -> Type where
 20 |     ||| A proof that the satisfying element is the first one in the `Vect`
 21 |     Here  : {0 xs : Vect n a} -> p x -> Any p (x :: xs)
 22 |     ||| A proof that the satsifying element is in the tail of the `Vect`
 23 |     There : {0 xs : Vect n a} -> Any p xs -> Any p (x :: xs)
 24 |
 25 | namespace All
 26 |
 27 |   ||| A proof that all elements of a vector satisfy a property. It is a list of
 28 |   ||| proofs, corresponding element-wise to the `Vect`.
 29 |   public export
 30 |   data All : (0 p : a -> Type) -> Vect n a -> Type where
 31 |     Nil  : All p Nil
 32 |     (::) : {0 xs : Vect n a} -> p x -> All p xs -> All p (x :: xs)
 33 |
 34 | ------------------------------------------------------------------------
 35 | -- Basic properties
 36 |
 37 | namespace Any
 38 |
 39 |   export
 40 |   All (Uninhabited . p) xs => Uninhabited (Any p xs) where
 41 |     uninhabited @{s::ss} (Here y)  = uninhabited y
 42 |     uninhabited @{s::ss} (There y) = uninhabited y
 43 |
 44 |   ||| Eliminator for `Any`
 45 |   public export
 46 |   anyElim : {0 xs : Vect n a} -> {0 p : a -> Type} -> (Any p xs -> b) -> (p x -> b) -> Any p (x :: xs) -> b
 47 |   anyElim _ f (Here p) = f p
 48 |   anyElim f _ (There p) = f p
 49 |
 50 |   ||| Given a decision procedure for a property, determine if an element of a
 51 |   ||| vector satisfies it.
 52 |   |||
 53 |   ||| @ p the property to be satisfied
 54 |   ||| @ dec the decision procedure
 55 |   ||| @ xs the vector to examine
 56 |   public export
 57 |   any : (dec : (x : a) -> Dec (p x)) -> (xs : Vect n a) -> Dec (Any p xs)
 58 |   any _ Nil = No uninhabited
 59 |   any p (x::xs) with (p x)
 60 |     any p (x::xs) | Yes prf = Yes (Here prf)
 61 |     any p (x::xs) | No prf =
 62 |       case any p xs of
 63 |         Yes prf' => Yes (There prf')
 64 |         No prf' => No (anyElim prf' prf)
 65 |
 66 |   export
 67 |   mapProperty : (f : forall x. p x -> q x) -> Any p l -> Any q l
 68 |   mapProperty f (Here p)  = Here (f p)
 69 |   mapProperty f (There p) = There (mapProperty f p)
 70 |
 71 |   ||| Forget the membership proof
 72 |   public export
 73 |   toDPair : {xs : Vect n a} -> Any p xs -> DPair a p
 74 |   toDPair (Here prf) = (_ ** prf)
 75 |   toDPair (There p)  = toDPair p
 76 |
 77 |   export
 78 |   toExists : Any p xs -> Exists p
 79 |   toExists (Here prf)  = Evidence _ prf
 80 |   toExists (There prf) = toExists prf
 81 |
 82 |   ||| Get the bounded numeric position of the element satisfying the predicate
 83 |   public export
 84 |   anyToFin : {0 xs : Vect n a} -> Any p xs -> Fin n
 85 |   anyToFin (Here _) = FZ
 86 |   anyToFin (There later) = FS (anyToFin later)
 87 |
 88 |   ||| `anyToFin`'s return type satisfies the predicate
 89 |   export
 90 |   anyToFinCorrect : {0 xs : Vect n a} ->
 91 |                     (witness : Any p xs) ->
 92 |                     p (anyToFin witness `index` xs)
 93 |   anyToFinCorrect (Here prf) = prf
 94 |   anyToFinCorrect (There later) = anyToFinCorrect later
 95 |
 96 |   public export
 97 |   anyToFinV : Any {n} p xs -> (idx : Fin n ** p $ index idx xs)
 98 |   anyToFinV $ Here x  = (FZ ** x)
 99 |   anyToFinV $ There x = let (idx ** v= anyToFinV x in (FS idx ** v)
100 |
101 |   public export
102 |   pushOut : Functor p => Any (p . q) xs -> p $ Any q xs
103 |   pushOut @{fp} (Here v)  = map @{fp} Here v
104 |   pushOut @{fp} (There n) = map @{fp} There $ pushOut n
105 |
106 |   export
107 |   All (Show . p) xs => Show (Any p xs) where
108 |     showPrec d @{s::ss} (Here x)  = showCon d "Here"  $ showArg x
109 |     showPrec d @{s::ss} (There x) = showCon d "There" $ showArg x
110 |
111 |   export
112 |   All (Eq . p) xs => Eq (Any p xs) where
113 |     (==) @{s::ss} (Here x)  (Here y)  = x == y
114 |     (==) @{s::ss} (There x) (There y) = x == y
115 |     (==) _ _ = False
116 |
117 | namespace All
118 |
119 |   export
120 |   notAllHere : {0 p : a -> Type} -> {xs : Vect n a} -> Not (p x) -> Not (All p (x :: xs))
121 |   notAllHere _ Nil impossible
122 |   notAllHere np (p :: _) = np p
123 |
124 |   export
125 |   notAllThere : {0 p : a -> Type} -> {xs : Vect n a} -> Not (All p xs) -> Not (All p (x :: xs))
126 |   notAllThere _ Nil impossible
127 |   notAllThere np (_ :: ps) = np ps
128 |
129 |   ||| Given a decision procedure for a property, decide whether all elements of
130 |   ||| a vector satisfy it.
131 |   |||
132 |   ||| @ p the property
133 |   ||| @ dec the decision procedure
134 |   ||| @ xs the vector to examine
135 |   public export
136 |   all : (dec : (x : a) -> Dec (p x)) -> (xs : Vect n a) -> Dec (All p xs)
137 |   all _ Nil = Yes Nil
138 |   all d (x::xs) with (d x)
139 |     all d (x::xs) | No prf = No (notAllHere prf)
140 |     all d (x::xs) | Yes prf =
141 |       case all d xs of
142 |         Yes prf' => Yes (prf :: prf')
143 |         No prf' => No (notAllThere prf')
144 |
145 |   export
146 |   Either (Uninhabited $ p x) (Uninhabited $ All p xs) => Uninhabited (All p $ x::xs) where
147 |     uninhabited @{Left  _} (px::pxs) = uninhabited px
148 |     uninhabited @{Right _} (px::pxs) = uninhabited pxs
149 |
150 |   export
151 |   mapProperty : (f : forall x. p x -> q x) -> All p l -> All q l
152 |   mapProperty f [] = []
153 |   mapProperty f (p::pl) = f p :: mapProperty f pl
154 |
155 |   ||| A variant of `mapProperty` that also allows accessing
156 |   ||| the values of `xs` that the corresponding `ps` prove `p` about.
157 |   export
158 |   mapPropertyRelevant : {xs : Vect n a} ->
159 |                         (f : (x : a) -> p x -> q x) ->
160 |                         (ps : All p xs) ->
161 |                         All q xs
162 |   mapPropertyRelevant f [] = []
163 |   mapPropertyRelevant f (p :: ps) = f _ p :: mapPropertyRelevant f ps
164 |
165 |   public export
166 |   imapProperty : {0 a : Type}
167 |               -> {0 p,q : a -> Type}
168 |               -> (0 i : a -> Type)
169 |               -> (f : {0 x : a} -> i x => p x -> q x)
170 |               -> {0 as : Vect n a}
171 |               -> All i as => All p as -> All q as
172 |   imapProperty _ _              []      = []
173 |   imapProperty i f @{ix :: ixs} (x::xs) = f @{ix} x :: imapProperty i f @{ixs} xs
174 |
175 |   ||| If `All` witnesses a property that does not depend on the vector `xs`
176 |   ||| it's indexed by, then it is really a `Vect`.
177 |   public export
178 |   forget : All (const p) {n} xs -> Vect n p
179 |   forget []      = []
180 |   forget (x::xs) = x :: forget xs
181 |
182 |   ||| Any `Vect` can be lifted to become an `All`
183 |   ||| witnessing the presence of elements of the `Vect`'s type.
184 |   public export
185 |   remember : (xs : Vect n ty) -> All (const ty) xs
186 |   remember [] = []
187 |   remember (x :: xs) = x :: remember xs
188 |
189 |   export
190 |   forgetRememberId : (xs : Vect n ty) -> forget (remember xs) = xs
191 |   forgetRememberId [] = Refl
192 |   forgetRememberId (x :: xs) = cong (x ::) (forgetRememberId xs)
193 |
194 |   public export
195 |   castAllConst : {0 xs, ys : Vect n a} -> All (const ty) xs -> All (const ty) ys
196 |   castAllConst [] = rewrite invertVectZ ys in []
197 |   castAllConst (x :: xs) = rewrite invertVectS ys in x :: castAllConst xs
198 |
199 |   export
200 |   rememberForgetId : (vs : All (const ty) xs) ->
201 |     castAllConst (remember (forget vs)) === vs
202 |   rememberForgetId [] = Refl
203 |   rememberForgetId (x :: xs) = cong (x ::) (rememberForgetId xs)
204 |
205 |   export
206 |   zipPropertyWith : (f : {0 x : a} -> p x -> q x -> r x) ->
207 |                     All p xs -> All q xs -> All r xs
208 |   zipPropertyWith f [] [] = []
209 |   zipPropertyWith f (px :: pxs) (qx :: qxs)
210 |     = f px qx :: zipPropertyWith f pxs qxs
211 |
212 |   ||| A `Traversable`'s `traverse` for `All`,
213 |   ||| for traversals that don't care about the values of the associated `Vect`.
214 |   export
215 |   traverseProperty : Applicative f =>
216 |                      {0 xs : Vect n a} ->
217 |                      (forall x. p x -> f (q x)) ->
218 |                      All p xs ->
219 |                      f (All q xs)
220 |   traverseProperty f [] = pure []
221 |   traverseProperty f (x :: xs) = [| f x :: traverseProperty f xs |]
222 |
223 |   ||| A `Traversable`'s `traverse` for `All`,
224 |   ||| in case the elements of the `Vect` that the `All` is proving `p` about are also needed.
225 |   export
226 |   traversePropertyRelevant : Applicative f =>
227 |                              {xs : Vect n a} ->
228 |                              ((x : a) -> p x -> f (q x)) ->
229 |                              All p xs ->
230 |                              f (All q xs)
231 |   traversePropertyRelevant f [] = pure []
232 |   traversePropertyRelevant f (x :: xs) = [| f _ x :: traversePropertyRelevant f xs |]
233 |
234 |   export
235 |   consInjective : {0 xs, ys: All p ts} -> {0 x, y: p a} -> (x :: xs = y :: ys) -> (x = y, xs = ys)
236 |   consInjective Refl = (Refl, Refl)
237 |
238 |   public export
239 |   tabulate : {n : _} ->
240 |              {0 xs : Vect n _} ->
241 |              (f : (ix : Fin n) -> p (ix `index` xs)) ->
242 |              All p {n} xs
243 |   tabulate {xs = []} f = []
244 |   tabulate {xs = _ :: _} f = f FZ :: tabulate (\ix => f (FS ix))
245 |
246 |   public export
247 |   (++) : (axs : All p xs) -> (ays : All p ys) -> All p (xs ++ ys)
248 |   [] ++ ays = ays
249 |   (ax :: axs) ++ ays = ax :: (axs ++ ays)
250 |
251 |   export
252 |   All (Show . p) xs => Show (All p xs) where
253 |     show pxs = "[" ++ show' "" pxs ++ "]"
254 |       where
255 |         show' : String -> All (Show . p) xs' => All p xs' -> String
256 |         show' acc @{[]} [] = acc
257 |         show' acc @{[_]} [px] = acc ++ show px
258 |         show' acc @{_ :: _} (px :: pxs) = show' (acc ++ show px ++ ", ") pxs
259 |
260 |   export
261 |   All (DecEq . p) xs => DecEq (All p xs) where
262 |     decEq [] [] = Yes Refl
263 |     decEq @{deq :: deqs} (x :: xs) (y :: ys) with (decEq x y)
264 |       decEq @{deq :: deqs} (x :: xs) (y :: ys) | (Yes prf) with (decEq xs ys)
265 |         decEq @{deq :: deqs} (x :: xs) (y :: ys) | (Yes prf) | (Yes prf') =
266 |           Yes (rewrite prf in rewrite prf' in Refl)
267 |         decEq @{deq :: deqs} (x :: xs) (y :: ys) | (Yes prf) | (No contra) =
268 |           No (contra . snd . consInjective)
269 |       decEq @{deq :: deqs} (x :: xs) (y :: ys) | (No contra) =
270 |         No (contra . fst . consInjective)
271 |
272 |   export
273 |   All (Eq . p) xs => Eq (All p xs) where
274 |     (==)           [] []             = True
275 |     (==) @{_ :: _} (h1::t1) (h2::t2) = h1 == h2 && t1 == t2
276 |
277 |   %hint
278 |   allEq : All (Ord . p) xs => All (Eq . p) xs
279 |   allEq @{[]}     = []
280 |   allEq @{_ :: _} = %search :: allEq
281 |
282 |   export
283 |   All (Ord . p) xs => Ord (All p xs) where
284 |     compare            [] []            = EQ
285 |     compare @{_ :: _} (h1::t1) (h2::t2) = case compare h1 h2 of
286 |       EQ => compare t1 t2
287 |       o  => o
288 |
289 |   export
290 |   All (Semigroup . p) xs => Semigroup (All p xs) where
291 |     (<+>)           [] [] = []
292 |     (<+>) @{_ :: _} (h1::t1) (h2::t2) = (h1 <+> h2) :: (t1 <+> t2)
293 |
294 |   %hint
295 |   allSemigroup : All (Monoid . p) xs => All (Semigroup . p) xs
296 |   allSemigroup @{[]}     = []
297 |   allSemigroup @{_ :: _} = %search :: allSemigroup
298 |
299 |   export
300 |   All (Monoid . p) xs => Monoid (All p xs) where
301 |     neutral @{[]}   = []
302 |     neutral @{_::_} = neutral :: neutral
303 |
304 |   ||| A heterogeneous vector of arbitrary types
305 |   public export
306 |   HVect : Vect n Type -> Type
307 |   HVect = All id
308 |
309 |   ||| Take the first element.
310 |   public export
311 |   head : All p (x :: xs) -> p x
312 |   head (y :: _) = y
313 |
314 |   ||| Take all but the first element.
315 |   public export
316 |   tail : All p (x :: xs) -> All p xs
317 |   tail (_ :: ys) = ys
318 |
319 |   ||| Drop the first n elements given knowledge that
320 |   ||| there are at least n elements available.
321 |   export
322 |   drop : {0 m : _} -> (n : Nat) -> {0 xs : Vect (n + m) a} -> All p xs -> All p (the (Vect m a) (Vect.drop n xs))
323 |   drop 0 ys = ys
324 |   drop (S k) (y :: ys) = drop k ys
325 |
326 |   ||| Drop up to the first l elements, stopping early
327 |   ||| if all elements have been dropped.
328 |   export
329 |   drop' : {0 k : _} -> {0 xs : Vect k _} -> (l : Nat) -> All p xs -> All p (Vect.drop' l xs)
330 |   drop' 0 ys = rewrite minusZeroRight k in ys
331 |   drop' (S k) [] = []
332 |   drop' (S k) (y :: ys) = drop' k ys
333 |
334 |   ||| Extract an element from an All.
335 |   |||
336 |   ||| ```idris example
337 |   ||| > index 0 (the (HVect _) [1, "string"])
338 |   ||| 1
339 |   ||| ```
340 |   export
341 |   index : (i : Fin k) -> All p ts -> p (index i ts)
342 |   index FZ (x :: xs) = x
343 |   index (FS j) (x :: xs) = index j xs
344 |
345 |   ||| Delete an element from an All at the given position.
346 |   |||
347 |   ||| ```idris example
348 |   ||| > deleteAt 0 (the (HVect _) [1, "string"])
349 |   ||| ["string"]
350 |   ||| ```
351 |   export
352 |   deleteAt : (i : Fin (S l)) -> All p ts -> All p (deleteAt i ts)
353 |   deleteAt FZ (x :: xs) = xs
354 |   deleteAt (FS FZ) (x :: (y :: xs)) = x :: xs
355 |   deleteAt (FS (FS j)) (x :: (y :: xs)) = x :: deleteAt (FS j) (y :: xs)
356 |
357 |   ||| Replace an element in an All at the given position.
358 |   |||
359 |   ||| ```idris example
360 |   ||| > replaceAt 0 "firstString" (the (HVect _) [1, "string"])
361 |   ||| ["firstString", "string"]
362 |   ||| ```
363 |   export
364 |   replaceAt : (i : Fin k) ->
365 |               (x : p t) ->
366 |               All p ts ->
367 |               All p (replaceAt i t ts)
368 |   replaceAt FZ y (x :: xs) = y :: xs
369 |   replaceAt (FS j) y (x :: xs) = x :: replaceAt j y xs
370 |
371 |   ||| Update an element in an All at the given position.
372 |   |||
373 |   ||| ```idris example
374 |   ||| > updateAt 0 (const True) (the (HVect _) [1, "string"])
375 |   ||| [True, "string"]
376 |   ||| ```
377 |   export
378 |   updateAt : (i : Fin k) ->
379 |              (p (index i ts) -> p t) ->
380 |              All p ts ->
381 |              All p (replaceAt i t ts)
382 |   updateAt FZ f (x :: xs) = f x :: xs
383 |   updateAt (FS j) f (x :: xs) = x :: updateAt j f xs
384 |
385 |   ||| Extract an element of an All.
386 |   |||
387 |   ||| ```idris example
388 |   ||| > get [1, "string"] {p = Here}
389 |   ||| 1
390 |   ||| ```
391 |   export
392 |   get : All p ts -> Elem x ts -> p x
393 |   get (x :: xs) Here = x
394 |   get (x :: xs) (There e') = get xs e'
395 |
396 |   ||| Replace an element of an All.
397 |   |||
398 |   ||| ```idris example
399 |   ||| > replaceElem 2 [1, "string"]
400 |   ||| [2, "string"]
401 |   ||| ```
402 |   export
403 |   replaceElem : All p ts -> (e : Elem t ts) -> p t' -> All p (replaceByElem ts e t')
404 |   replaceElem (x :: xs) Here y = y :: xs
405 |   replaceElem (x :: xs) (There p') y = x :: replaceElem xs p' y
406 |
407 |   ||| Update an element of an All.
408 |   |||
409 |   ||| ```idris example
410 |   ||| > updateElem (const "hello world!") [1, "string"]
411 |   ||| [1, "hello world!"]
412 |   ||| ```
413 |   public export
414 |   updateElem : {0 p : _} -> (p t -> p t') -> All p ts -> (e : Elem t ts) -> All p (replaceByElem ts e t')
415 |   updateElem f (x :: xs)  Here = f x :: xs
416 |   updateElem f (x :: xs) (There p') = x :: updateElem f xs p'
417 |
418 |   ||| Push in the property from the list level with element level
419 |   public export
420 |   pushIn : (xs : Vect n a) -> (0 _ : All p xs) -> Vect n $ Subset a p
421 |   pushIn []      []      = []
422 |   pushIn (x::xs) (p::ps) = Element x p :: pushIn xs ps
423 |
424 |   ||| Pull the elementwise property out to the list level
425 |   public export
426 |   pullOut : (xs : Vect n $ Subset a p) -> Subset (Vect n a) (All p)
427 |   pullOut [] = Element [] []
428 |   pullOut (Element x p :: xs) = let Element ss ps = pullOut xs in Element (x::ss) (p::ps)
429 |
430 |   export
431 |   pushInOutInverse : (xs : Vect n a) -> (0 prf : All p xs) -> pullOut (pushIn xs prf) = Element xs prf
432 |   pushInOutInverse [] [] = Refl
433 |   pushInOutInverse (x::xs) (p::ps) = rewrite pushInOutInverse xs ps in Refl
434 |
435 |   export
436 |   pushOutInInverse : (xs : Vect n $ Subset a p) -> uncurry All.pushIn (pullOut xs) = xs
437 |   pushOutInInverse [] = Refl
438 |   pushOutInInverse (Element x p :: xs) with (pushOutInInverse xs)
439 |     pushOutInInverse (Element x p :: xs) | subprf with (pullOut xs)
440 |       pushOutInInverse (Element x p :: xs) | subprf | Element ss ps = rewrite subprf in Refl
441 |
442 |   public export
443 |   pushOut : Applicative p => All (p . q) xs -> p $ All q xs
444 |   pushOut []      = pure []
445 |   pushOut (x::xs) = [| x :: pushOut xs |]
446 |
447 | ------------------------------------------------------------------------
448 | -- Relationships between all and any
449 |
450 | ||| If there does not exist an element that satifies the property, then it is
451 | ||| the case that all elements do not satisfy.
452 | export
453 | negAnyAll : {xs : Vect n a} -> Not (Any p xs) -> All (Not . p) xs
454 | negAnyAll {xs=Nil} _ = Nil
455 | negAnyAll {xs=(x::xs)} f = (f . Here) :: negAnyAll (f . There)
456 |
457 | ||| If there exists an element that doesn't satify the property, then it is
458 | ||| not the case that all elements satisfy it.
459 | export
460 | anyNegAll : Any (Not . p) xs -> Not (All p xs)
461 | anyNegAll (Here ctra) (p::_)  = ctra p
462 | anyNegAll (There np)  (_::ps) = anyNegAll np ps
463 |
464 | ||| If none of the elements satisfy the property, then not any single one can.
465 | export
466 | allNegAny : All (Not . p) xs -> Not (Any p xs)
467 | allNegAny [] p = absurd p
468 | allNegAny (np :: npxs) (Here p) = absurd (np p)
469 | allNegAny (np :: npxs) (There p) = allNegAny npxs p
470 |
471 | public export
472 | allAnies : {xs : Vect n a} -> All p xs -> Vect n (Any p xs)
473 | allAnies [] = []
474 | allAnies (x::xs) = Here x :: map There (allAnies xs)
475 |
476 | public export
477 | altAll : Alternative p => All (p . q) xs -> p $ Any q xs
478 | altAll []      = empty
479 | altAll (a::as) = Here <$> a <|> There <$> altAll as
480 |