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