0 | module Data.SnocList.Quantifiers
  1 |
  2 | import Data.DPair
  3 | import Data.Fin
  4 | import Data.SnocList
  5 | import Data.SnocList.Elem
  6 |
  7 | %default total
  8 |
  9 | ------------------------------------------------------------------------
 10 | -- Types and basic properties
 11 |
 12 | namespace Any
 13 |
 14 |   ||| A proof that some element of a snoclist satisfies some property
 15 |   |||
 16 |   ||| @ p the property to be satisfied
 17 |   public export
 18 |   data Any : (0 p : a -> Type) -> SnocList a -> Type where
 19 |     ||| A proof that the rightmost element in the `SnocList` satisfies p
 20 |     Here  : {0 xs : SnocList a} -> p x -> Any p (xs :< x)
 21 |     ||| A proof that there is an element the tail of the `SnocList` satisfying p
 22 |     There : {0 xs : SnocList a} -> Any p xs -> Any p (xs :< x)
 23 |
 24 | namespace All
 25 |
 26 |   ||| A proof that all elements of a list satisfy a property. It is a list of
 27 |   ||| proofs, corresponding element-wise to the `List`.
 28 |   public export
 29 |   data All : (0 p : a -> Type) -> SnocList a -> Type where
 30 |     Lin  : All p [<]
 31 |     (:<) : All p xs -> p x -> All p (xs :< x)
 32 |
 33 | ------------------------------------------------------------------------
 34 | -- Types and basic properties
 35 |
 36 | namespace Any
 37 |
 38 |   export
 39 |   All (Uninhabited . p) xs => Uninhabited (Any p xs) where
 40 |     uninhabited @{ss:<s} (Here y)  = uninhabited y
 41 |     uninhabited @{ss:<s} (There y) = uninhabited y
 42 |
 43 |   ||| Modify the property given a pointwise function
 44 |   public export
 45 |   mapProperty : (f : {0 x : a} -> p x -> q x) -> Any p l -> Any q l
 46 |   mapProperty f (Here p) = Here (f p)
 47 |   mapProperty f (There p) = There (mapProperty f p)
 48 |
 49 |   ||| Given a decision procedure for a property, determine if an element of a
 50 |   ||| list satisfies it.
 51 |   |||
 52 |   ||| @ p the property to be satisfied
 53 |   ||| @ dec the decision procedure
 54 |   ||| @ xs the list to examine
 55 |   public export
 56 |   any : (dec : (x : a) -> Dec (p x)) -> (xs : SnocList a) -> Dec (Any p xs)
 57 |   any _ Lin = No uninhabited
 58 |   any p (xs :< x) with (p x)
 59 |     any p (xs :< x) | Yes px = Yes (Here px)
 60 |     any p (xs :< x) | No npx =
 61 |       case any p xs of
 62 |         Yes pxs => Yes (There pxs)
 63 |         No npxs => No $ \case
 64 |           Here px => npx px
 65 |           There pxs => npxs pxs
 66 |
 67 |   ||| Forget the membership proof
 68 |   public export
 69 |   toDPair : {xs : SnocList a} -> Any p xs -> DPair a p
 70 |   toDPair (Here prf) = (_ ** prf)
 71 |   toDPair (There p)  = toDPair p
 72 |
 73 |   ||| Forget the membership proof
 74 |   export
 75 |   toExists : Any p xs -> Exists p
 76 |   toExists (Here prf) = Evidence _ prf
 77 |   toExists (There prf) = toExists prf
 78 |
 79 |   public export
 80 |   anyToFin : Any p xs -> Fin $ length xs
 81 |   anyToFin (Here _)      = FZ
 82 |   anyToFin (There later) = FS (anyToFin later)
 83 |
 84 |   public export
 85 |   pushOut : Functor p => Any (p . q) xs -> p $ Any q xs
 86 |   pushOut @{fp} (Here v)  = map @{fp} Here v
 87 |   pushOut @{fp} (There n) = map @{fp} There $ pushOut n
 88 |
 89 |   export
 90 |   All (Show . p) xs => Show (Any p xs) where
 91 |     showPrec d @{ss:<s} (Here x)  = showCon d "Here"  $ showArg x
 92 |     showPrec d @{ss:<s} (There x) = showCon d "There" $ showArg x
 93 |
 94 |   export
 95 |   All (Eq . p) xs => Eq (Any p xs) where
 96 |     (==) @{ss:<s} (Here x)  (Here y)  = x == y
 97 |     (==) @{ss:<s} (There x) (There y) = x == y
 98 |     (==) _ _ = False
 99 |
100 | namespace All
101 |
102 |   public export
103 |   length : All p xs -> Nat
104 |   length [<] = 0
105 |   length (xs :< x) = S (length xs)
106 |
107 |   public export
108 |   (++) : All p xs -> All p ys -> All p (xs ++ ys)
109 |   pxs ++ [<] = pxs
110 |   pxs ++ (pys :< py) = (pxs ++ pys) :< py
111 |
112 |   export
113 |   lengthUnfold : (pxs : All p xs) -> length pxs === length xs
114 |   lengthUnfold [<] = Refl
115 |   lengthUnfold (pxs :< _) = cong S (lengthUnfold pxs)
116 |
117 |
118 |   export
119 |   Either (Uninhabited (p x)) (Uninhabited (All p xs)) => Uninhabited (All p (xs :< x)) where
120 |     uninhabited @{Left  _} (pxs :< px) = uninhabited px
121 |     uninhabited @{Right _} (pxs :< px) = uninhabited pxs
122 |
123 |   ||| Modify the property given a pointwise function
124 |   public export
125 |   mapProperty : (f : {0 x : a} -> p x -> q x) -> All p l -> All q l
126 |   mapProperty f [<] = [<]
127 |   mapProperty f (pxs :< px) = mapProperty f pxs :< f px
128 |
129 |   ||| Modify the property given a pointwise interface function
130 |   public export
131 |   imapProperty : (0 i : Type -> Type)
132 |               -> (f : {0 a : Type} -> i a => p a -> q a)
133 |               -> {0 types : SnocList Type}
134 |               -> All i types => All p types -> All q types
135 |   imapProperty i f @{[<]} [<] = [<]
136 |   imapProperty i f @{ixs :< ix} (xs :< x) = imapProperty i f @{ixs} xs :< f @{ix} x
137 |
138 |   ||| Forget property source for a homogeneous collection of properties
139 |   public export
140 |   forget : All (const type) types -> SnocList type
141 |   forget [<] = [<]
142 |   forget (xs :< x) = forget xs :< x
143 |
144 |   ||| Given a decision procedure for a property, decide whether all elements of
145 |   ||| a list satisfy it.
146 |   |||
147 |   ||| @ p the property
148 |   ||| @ dec the decision procedure
149 |   ||| @ xs the list to examine
150 |   public export
151 |   all : (dec : (x : a) -> Dec (p x)) -> (xs : SnocList a) -> Dec (All p xs)
152 |   all _ Lin = Yes Lin
153 |   all d (xs :< x) with (d x)
154 |     all d (xs :< x) | No npx = No $ \(_ :< px) => npx px
155 |     all d (xs :< x) | Yes px =
156 |       case all d xs of
157 |         Yes pxs => Yes (pxs :< px)
158 |         No npxs => No $ \(pxs :< _) => npxs pxs
159 |
160 |   export
161 |   zipPropertyWith : (f : {0 x : a} -> p x -> q x -> r x) ->
162 |                     All p xs -> All q xs -> All r xs
163 |   zipPropertyWith f [<] [<] = [<]
164 |   zipPropertyWith f (pxs :< px) (qxs :< qx)
165 |     = zipPropertyWith f pxs qxs :< f px qx
166 |
167 |   export
168 |   All Show (map p xs) => Show (All p xs) where
169 |     show pxs = concat ("[<" :: show' pxs ["]"])
170 |       where
171 |         show' : All Show (map p xs') => All p xs' ->
172 |                 List String -> List String
173 |         show' @{[<]} [<] = id
174 |         show' @{[<_]} [<px] = (show px ::)
175 |         show' @{_ :< _} (pxs :< px) = show' pxs . (", " ::) . (show px ::)
176 |
177 |   export
178 |   All (Eq . p) xs => Eq (All p xs) where
179 |     (==)           [<]      [<]      = True
180 |     (==) @{_ :< _} (t1:<h1) (t2:<h2) = h1 == h2 && t1 == t2
181 |
182 |   %hint
183 |   allEq : All (Ord . p) xs => All (Eq . p) xs
184 |   allEq @{[<]}    = [<]
185 |   allEq @{_ :< _} = allEq :< %search
186 |
187 |   export
188 |   All (Ord . p) xs => Ord (All p xs) where
189 |     compare           [<]      [<]      = EQ
190 |     compare @{_ :< _} (t1:<h1) (t2:<h2) = case compare h1 h2 of
191 |       EQ => compare t1 t2
192 |       o  => o
193 |
194 |   export
195 |   All (Semigroup . p) xs => Semigroup (All p xs) where
196 |     (<+>)           [<]      [<]      = [<]
197 |     (<+>) @{_ :< _} (t1:<h1) (t2:<h2) = (t1 <+> t2) :< (h1 <+> h2)
198 |
199 |   %hint
200 |   allSemigroup : All (Monoid . p) xs => All (Semigroup . p) xs
201 |   allSemigroup @{[<]}    = [<]
202 |   allSemigroup @{_ :< _} = allSemigroup :< %search
203 |
204 |   export
205 |   All (Monoid . p) xs => Monoid (All p xs) where
206 |     neutral @{[<]}  = [<]
207 |     neutral @{_:<_} = neutral :< neutral
208 |
209 |   ||| A heterogeneous snoc-list of arbitrary types
210 |   public export
211 |   HSnocList : SnocList Type -> Type
212 |   HSnocList = All id
213 |
214 |   ||| Push in the property from the list level with element level
215 |   public export
216 |   pushIn : (xs : SnocList a) -> (0 _ : All p xs) -> SnocList $ Subset a p
217 |   pushIn [<]     [<]     = [<]
218 |   pushIn (xs:<x) (ps:<p) = pushIn xs ps :< Element x p
219 |
220 |   ||| Pull the elementwise property out to the list level
221 |   public export
222 |   pullOut : (xs : SnocList $ Subset a p) -> Subset (SnocList a) (All p)
223 |   pullOut [<]                 = Element [<] [<]
224 |   pullOut (xs :< Element x p) = let Element ss ps = pullOut xs in Element (ss:<x) (ps:<p)
225 |
226 |   export
227 |   pushInOutInverse : (xs : SnocList a) -> (0 prf : All p xs) -> pullOut (pushIn xs prf) = Element xs prf
228 |   pushInOutInverse [<] [<] = Refl
229 |   pushInOutInverse (xs:<x) (ps:<p) = rewrite pushInOutInverse xs ps in Refl
230 |
231 |   export
232 |   pushOutInInverse : (xs : SnocList $ Subset a p) -> uncurry All.pushIn (pullOut xs) = xs
233 |   pushOutInInverse [<] = Refl
234 |   pushOutInInverse (xs :< Element x p) with (pushOutInInverse xs)
235 |     pushOutInInverse (xs :< Element x p) | subprf with (pullOut xs)
236 |       pushOutInInverse (xs :< Element x p) | subprf | Element ss ps = rewrite subprf in Refl
237 |
238 |   ||| Given a proof of membership for some element, extract the property proof for it
239 |   public export
240 |   indexAll : Elem x xs -> All p xs -> p x
241 |   indexAll  Here     (_ :< px) = px
242 |   indexAll (There e) (pxs :< _) = indexAll e pxs
243 |
244 |   public export
245 |   pushOut : Applicative p => All (p . q) xs -> p $ All q xs
246 |   pushOut [<]     = pure [<]
247 |   pushOut (xs:<x) = [| pushOut xs :< x |]
248 |
249 | ------------------------------------------------------------------------
250 | -- Relationship between all and any
251 |
252 | ||| If there does not exist an element that satifies the property, then it is
253 | ||| the case that all elements do not satisfy it.
254 | export
255 | negAnyAll : {xs : SnocList a} -> Not (Any p xs) -> All (Not . p) xs
256 | negAnyAll {xs=[<]}     _ = [<]
257 | negAnyAll {xs=xs :< x} f = negAnyAll (f . There) :< (f . Here)
258 |
259 | ||| If there exists an element that doesn't satify the property, then it is
260 | ||| not the case that all elements satisfy it.
261 | export
262 | anyNegAll : Any (Not . p) xs -> Not (All p xs)
263 | anyNegAll (Here npx) (_ :< px) = npx px
264 | anyNegAll (There npxs)  (pxs :< _) = anyNegAll npxs pxs
265 |
266 | ||| If none of the elements satisfy the property, then not any single one can.
267 | export
268 | allNegAny : All (Not . p) xs -> Not (Any p xs)
269 | allNegAny [<] pxs = absurd pxs
270 | allNegAny (npxs :< npx) (Here px) = absurd (npx px)
271 | allNegAny (npxs :< npx) (There pxs) = allNegAny npxs pxs
272 |
273 | public export
274 | allAnies : All p xs -> SnocList (Any p xs)
275 | allAnies [<] = [<]
276 | allAnies (xs:<x) = map There (allAnies xs) :< Here x
277 |
278 | export
279 | altAll : Alternative p => All (p . q) xs -> p $ Any q xs
280 | altAll [<]     = empty
281 | altAll (as:<a) = Here <$> a <|> There <$> altAll as
282 |
283 | ||| If any `a` either satisfies p or q then given a Snoclist of as,
284 | ||| either all values satisfy p
285 | ||| or at least one of them sastifies q
286 | public export
287 | decide : ((x : a) -> Either (p x) (q x)) ->
288 |          (xs : SnocList a) -> Either (All p xs) (Any q xs)
289 | decide dec [<] = Left [<]
290 | decide dec (xs :< x) = case dec x of
291 |   Left px => case decide dec xs of
292 |     Left pxs => Left (pxs :< px)
293 |     Right pxs => Right (There pxs)
294 |   Right px => Right (Here px)
295 |