Idris2/libs/base/Data/List1/Quantifiers.idr
Thomas E. Hansen 268a3520f3 [ base ] Port most of List.Quantifiers to List1
This doesn't include `Interleaving` and `Split`.
2022-06-09 09:05:10 +02:00

244 lines
8.8 KiB
Idris

module Data.List1.Quantifiers
import Data.DPair
import Data.List1
import Data.List1.Elem
import Data.List.Quantifiers
%default total
------------------------------------------------------------------------
-- Types and basic properties
namespace Any
||| A proof that some element of a list satisfies some property
|||
||| @ p the property to be satisfied
public export
data Any : (0 p : a -> Type) -> List1 a -> Type where
||| A proof that the satisfying element is the first one in the `List1`
Here : {0 xs : List a} -> p x -> Any p (x ::: xs)
||| A proof that the satisfying element is in the tail of the `List1`
There : {0 xs : List a} -> Any p xs -> Any p (x ::: xs)
||| Modify the property given a pointwise function
export
mapProperty : {l : List1 a} -> (f : {0 x : a} -> p x -> q x) -> Any p l -> Any q l
mapProperty f (Here p) = Here (f p)
mapProperty f (There p) = There (mapProperty f p)
||| Given a decision procedure for a property, determine if an element of a
||| list satisfies it.
|||
||| @ p the property to be satisfied
||| @ dec the decision procedure
||| @ xs the list to examine
public export
any : (dec : (x : a) -> Dec (p x)) -> (xs : List1 a) -> Dec (Any p xs)
any p (head:::tail) with (p head)
any p (head:::tail) | Yes prf = Yes (Here prf)
any p (head:::tail) | No ctra =
case any p tail of
Yes prf' => Yes (There prf')
No ctra' => No $ \case
Here px => ctra px
There ptail => ctra' ptail
||| Forget the membership proof
export
toExists : {xs : List1 a} -> Any p xs -> Exists p
toExists (Here prf) = Evidence _ prf
toExists (There prf) = toExists prf
namespace All
||| A proof that all elements of a list satisfy a property. It is a list of
||| proofs, corresponding element-wise to the `List1`.
public export
data All : (0 p : a -> Type) -> List1 a -> Type where
(:::) : {0 xs : List a} -> p x -> All p xs -> All p (x ::: xs)
Either (Uninhabited $ p x) (Uninhabited $ All p xs) => Uninhabited (All p $ x:::xs) where
uninhabited @{Left _} (px:::pxs) = uninhabited px
uninhabited @{Right _} (px:::pxs) = uninhabited pxs
||| Modify the property given a pointwise function
export
mapProperty : {l : List1 a} -> (f : {0 x : a} -> p x -> q x) -> All p l -> All q l
mapProperty f (p:::pl) = f p ::: mapProperty f pl
||| Modify the property given a pointwise interface function
public export
imapProperty : (0 i : Type -> Type)
-> (f : {0 a : Type} -> i a => p a -> q a)
-> {0 types : List1 Type}
-> All i types => All p types -> All q types
imapProperty i f @{ix ::: ixs} (x ::: xs) = f @{ix} x ::: imapProperty i f @{ixs} xs
||| Forget property source for a homogeneous collection of properties
public export
forget : {types : List1 _} -> All (const type) types -> List1 type
forget (x ::: xs) = x ::: forget xs
||| Given a decision procedure for a property, decide whether all elements of
||| a list satisfy it.
|||
||| @ p the property
||| @ dec the decision procedure
||| @ xs the list to examine
public export
all : (dec : (x : a) -> Dec (p x)) -> (xs : List1 a) -> Dec (All p xs)
all d (head:::tail) with (d head)
all d (head:::tail) | No ctra = No $ \(p:::_) => ctra p
all d (head:::tail) | Yes prf =
case all d tail of
Yes prf' => Yes (prf ::: prf')
No ctra' => No $ \(_:::ps) => ctra' ps
export
zipPropertyWith : {xs : List1 _} -> (f : {0 x : a} -> p x -> q x -> r x) ->
All p xs -> All q xs -> All r xs
zipPropertyWith f (px ::: pxs) (qx ::: qxs)
= f px qx ::: zipPropertyWith f pxs qxs
--- export
--- {xs : List1 _} -> All Show (map p xs) => Show (All p xs) where
--- show pxs = "[" ++ show' "" pxs ++ "]"
--- where
--- show' : {xs' : List1 _} -> String -> All Show (map p xs') => All p xs' -> String
--- show' acc @{_ ::: []} (px ::: []) = acc ++ show px
--- show' acc @{_ ::: _} (px ::: pxs) = show' (acc ++ show px ++ ", ") pxs
||| A heterogeneous list of arbitrary types
public export
HList1 : List1 Type -> Type
HList1 = All id
------------------------------------------------------------------------
-- Relationship between all and any
||| If there does not exist an element that satifies the property, then it is
||| the case that all elements do not satisfy it.
export
negAnyAll : {xs : List1 a} -> Not (Any p xs) -> All (Not . p) xs
negAnyAll {xs=x:::xs} f = (f . Here) ::: negAnyAll (f . There)
||| If there exists an element that doesn't satify the property, then it is
||| not the case that all elements satisfy it.
export
anyNegAll : {xs : List1 _} -> Any (Not . p) xs -> Not (All p xs)
anyNegAll (Here ctra) (p:::_) = ctra p
anyNegAll (There np) (_:::ps) = anyNegAll np ps
||| If none of the elements satisfy the property, then not any single one can.
export
allNegAny : {xs : List1 _} -> All (Not . p) xs -> Not (Any p xs)
allNegAny (np ::: npxs) (Here p) = absurd (np p)
allNegAny (np ::: npxs) (There p) = allNegAny npxs p
||| Given a proof of membership for some element, extract the property proof for it
public export
indexAll : {xs : List1 _} -> Elem x xs -> All p xs -> p x
indexAll Here (p::: _) = p
indexAll (There e) (_:::ps) = indexAll e ps
--- Relations between listwise `All` and elementwise `Subset` ---
||| Push in the property from the list level with element level
public export
pushIn : (xs : List1 a) -> (0 _ : All p xs) -> List1 $ Subset a p
pushIn (x:::xs) (p:::ps) = Element x p ::: pushIn xs ps
||| Pull the elementwise property out to the list level
public export
pullOut : (xs : List1 $ Subset a p) -> Subset (List1 a) (All p)
pullOut (Element x p ::: xs) = let Element ss ps = pullOut xs in Element (x:::ss) (p:::ps)
export
pushInOutInverse : (xs : List1 a) -> (0 prf : All p xs) -> pullOut (pushIn xs prf) = Element xs prf
pushInOutInverse (x:::xs) (p:::ps) = rewrite pushInOutInverse xs ps in Refl
export
pushOutInInverse : (xs : List1 $ Subset a p) -> uncurry Quantifiers.pushIn (pullOut xs) = xs
pushOutInInverse (Element x p ::: xs) with (pushOutInInverse xs)
pushOutInInverse (Element x p ::: xs) | subprf with (pullOut xs)
pushOutInInverse (Element x p ::: xs) | subprf | Element ss ps = rewrite subprf in Refl
{-
------------------------------------------------------------------------
-- Partitioning lists according to All
||| Two lists, `xs` and `ys`, whose elements are interleaved in the list `xys`.
public export
data Interleaving : (xs, ys, xys : List a) -> Type where
Nil : Interleaving [] [] []
Left : Interleaving xs ys xys -> Interleaving (x :: xs) ys (x :: xys)
Right : Interleaving xs ys xys -> Interleaving xs (y :: ys) (y :: xys)
||| A record for storing the result of splitting a list `xys` according to some
||| property `p`.
||| The `prfs` and `contras` are related to the original list (`xys`) via
||| `Interleaving`.
|||
||| @ xys the list which has been split
||| @ p the property used for the split
public export
record Split {a : Type} (p : a -> Type) (xys : List a) where
constructor MkSplit
{ayes, naws : List a}
{auto interleaving : Interleaving ayes naws xys}
||| A proof that all elements in `ayes` satisfies the property used for the
||| split.
prfs : All p ayes
||| A proof that all elements in `naws` do not satisfy the property used for
||| the split.
contras : All (Not . p) naws
||| Split the list according to the given decidable property, putting the
||| resulting proofs and contras in an accumulator.
|||
||| @ dec a function which returns a decidable property
||| @ xs a list of elements to split
||| @ a the accumulator
public export
splitOnto : (dec : (x : a) -> Dec (p x))
-> (xs : List a)
-> (a : Split p acc)
-> Split p (reverseOnto acc xs)
splitOnto dec [] a = a
splitOnto dec (x :: xs) (MkSplit prfs contras) =
case dec x of
(Yes prf) => splitOnto dec xs (MkSplit (prf :: prfs) contras)
(No contra) => splitOnto dec xs (MkSplit prfs (contra :: contras))
||| Split the list according to the given decidable property, starting with an
||| empty accumulator.
||| Use `splitOnto` if you want to specify the accumulator.
|||
||| @ dec a function which returns a decidable property
||| @ xs a list of elements to split
||| @ a the accumulator
public export
split : (dec : (x : a) -> Dec (p x))
-> (xs : List a)
-> Split p (reverse xs)
split dec xs = splitOnto dec xs (MkSplit [] [])
||| If any `a` either satisfies p or q then given a List of as,
||| either all values satisfy p
||| or at least one of them sastifies q
public export
decide : ((x : a) -> Either (p x) (q x)) ->
(xs : List a) -> Either (All p xs) (Any q xs)
decide dec [] = Left []
decide dec (x :: xs) = case dec x of
Left px => case decide dec xs of
Left pxs => Left (px :: pxs)
Right pxs => Right (There pxs)
Right px => Right (Here px)
-}