mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-19 01:01:59 +03:00
173 lines
5.9 KiB
Idris
173 lines
5.9 KiB
Idris
module Data.List.Views.Extra
|
|
|
|
import Data.List
|
|
import Data.List.Reverse
|
|
import Data.List.Views
|
|
import Data.Nat
|
|
import Data.List.Equalities
|
|
|
|
%default total
|
|
|
|
||| Proof that two numbers differ by at most one
|
|
public export
|
|
data Balanced : Nat -> Nat -> Type where
|
|
BalancedZ : Balanced Z Z
|
|
BalancedL : Balanced (S Z) Z
|
|
BalancedRec : Balanced n m -> Balanced (S n) (S m)
|
|
|
|
%name Balanced bal, b
|
|
|
|
Uninhabited (Balanced Z (S k)) where
|
|
uninhabited BalancedZ impossible
|
|
uninhabited BalancedL impossible
|
|
uninhabited (BalancedRec rec) impossible
|
|
|
|
export
|
|
balancedPred : Balanced (S x) (S y) -> Balanced x y
|
|
balancedPred (BalancedRec pred) = pred
|
|
|
|
export
|
|
mkBalancedEq : {n, m : Nat} -> n = m -> Balanced n m
|
|
mkBalancedEq {n = 0} Refl = BalancedZ
|
|
mkBalancedEq {n = (S k)} Refl = BalancedRec $ mkBalancedEq {n = k} Refl
|
|
|
|
export
|
|
mkBalancedL : {n, m : Nat} -> n = S m -> Balanced n m
|
|
mkBalancedL {m = 0} Refl = BalancedL
|
|
mkBalancedL {m = S k} Refl = BalancedRec (mkBalancedL Refl)
|
|
|
|
||| View of a list split into two halves
|
|
|||
|
|
||| The lengths of the lists are guaranteed to differ by at most one
|
|
public export
|
|
data SplitBalanced : List a -> Type where
|
|
MkSplitBal
|
|
: {xs, ys : List a}
|
|
-> Balanced (length xs) (length ys)
|
|
-> SplitBalanced (xs ++ ys)
|
|
|
|
private
|
|
splitBalancedHelper
|
|
: (revLs : List a)
|
|
-> (rs : List a)
|
|
-> (doubleSkip : List a)
|
|
-> (length rs = length revLs + length doubleSkip)
|
|
-> SplitBalanced (reverse revLs ++ rs)
|
|
splitBalancedHelper revLs rs [] prf = MkSplitBal balancedLeftsAndRights
|
|
where
|
|
lengthsEqual : length rs = length revLs
|
|
lengthsEqual =
|
|
rewrite sym (plusZeroRightNeutral (length revLs)) in prf
|
|
balancedLeftsAndRights : Balanced (length (reverse revLs)) (length rs)
|
|
balancedLeftsAndRights =
|
|
rewrite reverseLength revLs in
|
|
rewrite lengthsEqual in
|
|
mkBalancedEq Refl
|
|
splitBalancedHelper revLs [] (x :: xs) prf =
|
|
absurd $
|
|
the (0 = S (plus (length revLs) (length xs)))
|
|
rewrite plusSuccRightSucc (length revLs) (length xs) in
|
|
prf
|
|
splitBalancedHelper revLs (x :: rs) [lastItem] prf =
|
|
rewrite appendAssociative (reverse revLs) [x] rs in
|
|
rewrite sym (reverseCons x revLs) in
|
|
MkSplitBal $
|
|
the (Balanced (length (reverseOnto [x] revLs)) (length rs)) $
|
|
rewrite reverseCons x revLs in
|
|
rewrite lengthSnoc x (reverse revLs) in
|
|
rewrite reverseLength revLs in
|
|
rewrite lengthsEqual in
|
|
mkBalancedL Refl
|
|
where
|
|
lengthsEqual : length rs = length revLs
|
|
lengthsEqual =
|
|
cong pred $
|
|
the (S (length rs) = S (length revLs)) $
|
|
rewrite plusCommutative 1 (length revLs) in prf
|
|
splitBalancedHelper revLs (x :: oneFurther) (_ :: (_ :: twoFurther)) prf =
|
|
rewrite appendAssociative (reverse revLs) [x] oneFurther in
|
|
rewrite sym (reverseCons x revLs) in
|
|
splitBalancedHelper (x :: revLs) oneFurther twoFurther $
|
|
cong pred $
|
|
the (S (length oneFurther) = S (S (plus (length revLs) (length twoFurther)))) $
|
|
rewrite plusSuccRightSucc (length revLs) (length twoFurther) in
|
|
rewrite plusSuccRightSucc (length revLs) (S (length twoFurther)) in
|
|
prf
|
|
|
|
||| Covering function for the `SplitBalanced`
|
|
|||
|
|
||| Constructs the view in linear time
|
|
export
|
|
splitBalanced : (input : List a) -> SplitBalanced input
|
|
splitBalanced input = splitBalancedHelper [] input input Refl
|
|
|
|
||| The `VList` view allows us to recurse on the middle of a list,
|
|
||| inspecting the front and back elements simultaneously.
|
|
public export
|
|
data VList : List a -> Type where
|
|
VNil : VList []
|
|
VOne : VList [x]
|
|
VCons : {x, y : a} -> {xs : List a} -> (rec : Lazy (VList xs)) -> VList (x :: xs ++ [y])
|
|
|
|
private
|
|
toVList
|
|
: (xs : List a)
|
|
-> SnocList ys
|
|
-> Balanced (length xs) (length ys)
|
|
-> VList (xs ++ ys)
|
|
toVList [] Empty BalancedZ = VNil
|
|
toVList [x] Empty BalancedL = VOne
|
|
toVList [] (Snoc x zs rec) prf =
|
|
absurd $
|
|
the (Balanced 0 (S (length zs))) $
|
|
rewrite sym (lengthSnoc x zs) in prf
|
|
toVList (x :: xs) (Snoc y ys srec) prf =
|
|
rewrite appendAssociative xs ys [y] in
|
|
VCons $
|
|
toVList xs srec $
|
|
balancedPred $
|
|
rewrite sym (lengthSnoc y ys) in prf
|
|
|
|
||| Covering function for `VList`
|
|
||| Constructs the view in linear time.
|
|
export
|
|
vList : (xs : List a) -> VList xs
|
|
vList xs with (splitBalanced xs)
|
|
vList (ys ++ zs) | (MkSplitBal prf) = toVList ys (snocList zs) prf
|
|
|
|
||| Lazy filtering of a list based on a predicate.
|
|
public export
|
|
data LazyFilterRec : List a -> Type where
|
|
Exhausted : (skip : List a) -> LazyFilterRec skip
|
|
Found : (skip : List a) -- initial non-matching elements
|
|
-> (head : a) -- first match
|
|
-> Lazy (LazyFilterRec rest)
|
|
-> LazyFilterRec (skip ++ (head :: rest))
|
|
|
|
||| Covering function for the LazyFilterRec view.
|
|
||| Constructs the view lazily in linear time.
|
|
total export
|
|
lazyFilterRec : (pred : (a -> Bool)) -> (xs : List a) -> LazyFilterRec xs
|
|
lazyFilterRec pred [] = Exhausted []
|
|
lazyFilterRec pred (x :: xs) with (pred x)
|
|
lazyFilterRec pred (x :: xs) | True = Found [] x (lazyFilterRec pred xs)
|
|
lazyFilterRec pred (x :: []) | False = Exhausted [x]
|
|
lazyFilterRec pred (x :: rest@(_ :: xs)) | False = filterHelper [x] rest
|
|
where
|
|
filterHelper
|
|
: (reverseOfSkipped : List a)
|
|
-> {auto prf1 : NonEmpty reverseOfSkipped}
|
|
-> (rest : List a)
|
|
-> {auto prf2 : NonEmpty rest}
|
|
-> LazyFilterRec (reverse reverseOfSkipped ++ rest)
|
|
filterHelper revSkipped (y :: xs) with (pred y)
|
|
filterHelper revSkipped (y :: xs) | True =
|
|
Found (reverse revSkipped) y (lazyFilterRec pred xs)
|
|
filterHelper revSkipped (y :: []) | False =
|
|
rewrite sym (reverseOntoSpec [y] revSkipped) in
|
|
Exhausted $ reverse (y :: revSkipped)
|
|
filterHelper revSkipped (y :: (z :: zs)) | False =
|
|
rewrite appendAssociative (reverse revSkipped) [y] (z :: zs) in
|
|
rewrite sym (reverseOntoSpec [y] revSkipped) in
|
|
filterHelper (y :: revSkipped) (z :: zs)
|