sized-vector 0.0.2.5 → 1.0.0.0
raw patch · 2 files changed
+363/−72 lines, 2 filesdep +equational-reasoning
Dependencies added: equational-reasoning
Files
- Data/Vector/Sized.hs +357/−67
- sized-vector.cabal +6/−5
Data/Vector/Sized.hs view
@@ -1,102 +1,295 @@-{-# LANGUAGE DataKinds, GADTs, MultiParamTypeClasses, PolyKinds #-}-{-# LANGUAGE StandaloneDeriving, TypeFamilies, TypeOperators #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds, GADTs, MultiParamTypeClasses, PolyKinds #-}+{-# LANGUAGE ScopedTypeVariables, StandaloneDeriving, TypeFamilies #-}+{-# LANGUAGE TypeOperators, NoImplicitPrelude #-} -- | Size-parameterized vector types and functions.-module Data.Vector.Sized ( Vector (..), sLength, length, append, foldr- , foldl, singleton, zipWith, zipWithSame, toList, fromList- , unsafeFromList, fromList', unsafeFromList'- , all, splitAt, takeAtMost, splitAtMost- , drop, take, map, head, tail, index) where-import Control.Applicative-import Data.Maybe-import Data.Singletons hiding (promote)-import Data.Type.Monomorphic-import Data.Type.Natural hiding (promote)-import Prelude hiding (all, drop, foldl, foldr, head, length, map,- splitAt, tail, take, zipWith)+module Data.Vector.Sized ( -- * Vectors and indices+ Vector (..)+ , Index(..), succIndex, indexToInt,+ -- * Conversion & Construction+ replicate, replicate', singleton, uncons,+ -- ** List+ fromList, fromList', unsafeFromList, unsafeFromList', toList,+ -- * Basic functions+ append, head, last, tail, null, length, sLength,+ -- * Vector transformations+ map, reverse, intersperse, transpose,+ -- * Reducing vectors (folds)+ foldl, foldl', foldl1, foldl1', foldr, foldr1,+ -- ** Special folds+ concat, and, or, any, all, sum, product, maximum, minimum,+ -- * Subvectors+ -- ** Extracting subvectors+ take, takeAtMost, drop, splitAt, splitAtMost, stripPrefix,+ -- * Searching vectors+ -- ** Searching by equality+ elem, notElem,+ -- ** Searching with a predicate+ find,+ -- * Indexing vectors+ (!!), (%!!), index, sIndex, elemIndex, sElemIndex+ , findIndex, sFindIndex, findIndices, sFindIndices+ , elemIndices, sElemIndices,+ -- * Zipping vectors+ zip, zipSame, zipWith, zipWithSame, unzip+ ) where+import Control.Applicative+import Data.Maybe+import Data.Type.Monomorphic+import Data.Type.Natural hiding (promote)+import qualified Prelude as P+import Prelude (Eq(..), Bool(..), Int, Show(..), (&&), Num(..)+ , (||), not, error, ($), (.), seq, fst, snd+ , flip, otherwise)+import Proof.Equational hiding (promote) +-- | Fixed-length list. data Vector (a :: *) (n :: Nat) where Nil :: Vector a Z (:-) :: a -> Vector a n -> Vector a (S n) infixr 5 :- +-- | Monomorphic representation of 'Vector' @a n@ is @[a]@.+instance Monomorphicable (Vector a) where+ type MonomorphicRep (Vector a) = [a]+ demote (Monomorphic vec) = toList vec+ promote [] = Monomorphic Nil+ promote (x:xs) =+ case promote xs of+ Monomorphic vec -> Monomorphic $ x :- vec++-- | Index type for list.+data Index (n :: Nat) where+ Index :: ((S m :<<= n) ~ True) => SNat m -> Index n++-- | Succ index number.+succIndex :: Index n -> Index (S n)+succIndex (Index n) = Index (sS n)++-- | Convert index into integer.+indexToInt :: Index n -> Int+indexToInt (Index n) = sNatToInt n++deriving instance Show (Index n)+ deriving instance Show a => Show (Vector a n) instance (Eq a) => Eq (Vector a n) where Nil == Nil = True (x :- xs) == (y :- ys) = x == y && xs == ys _ == _ = error "impossible!" -sLength :: Vector a n -> SNat n-sLength Nil = sZ-sLength (_ :- xs) = sS $ sLength xs--length :: Vector a n -> Int-length = sNatToInt . sLength--append :: Vector a n -> Vector a m -> Vector a (n :+: m)-append (x :- xs) ys = x :- append xs ys-append Nil ys = ys+--------------------------------------------------+-- Conversion & Construction+-------------------------------------------------- -foldr :: (a -> b -> b) -> b -> Vector a n -> b-foldr _ b Nil = b-foldr f a (x :- xs) = f x (foldr f a xs)+-- | 'replicate' @n x@ is a vector of length @n@ with @x@ the value of every element.+replicate :: SNat n -> a -> Vector a n+replicate SZ _ = Nil+replicate (SS n) a = a :- replicate n a -foldl :: (a -> b -> a) -> a -> Vector b n -> a-foldl _ a Nil = a-foldl f a (b :- bs) = foldl f (f a b) bs+-- | 'replicate', with the length inferred.+replicate' :: forall n a. SingRep n => a -> Vector a n+replicate' = replicate (sing :: SNat n) +-- | Construct a singleton vector. singleton :: a -> Vector a (S Z) singleton = (:- Nil) -zipWithSame :: (a -> b -> c) -> Vector a n -> Vector b n -> Vector c n-zipWithSame _ Nil Nil = Nil-zipWithSame f (x :- xs) (y :- ys) = f x y :- zipWithSame f xs ys-zipWithSame _ _ _ = error "cannot happen"--zipWith :: (a -> b -> c) -> Vector a n -> Vector b m -> Vector c (Min n m)-zipWith _ Nil Nil = Nil-zipWith _ Nil (_ :- _) = Nil-zipWith _ (_ :- _) Nil = Nil-zipWith f (x :- xs) (y :- ys) = f x y :- zipWith f xs ys--toList :: Vector a n -> [a]-toList = foldr (:) []+-- | Uncons the non-empty list.+uncons :: Vector a (S n) -> (a, Vector a n)+uncons (a :- as) = (a, as) +-- | Convert a list into a vector.+-- If a given list is shorter than the length, it returns @Nothing@. fromList :: SNat n -> [a] -> Maybe (Vector a n) fromList SZ _ = Just Nil fromList (SS n) (x:xs) = (x :-) <$> fromList n xs fromList _ _ = Nothing +-- | Unsafe version of 'fromList'.+-- If a given list is shorter than the length, it aborts. unsafeFromList :: SNat n -> [a] -> Vector a n unsafeFromList len = fromMaybe (error "Length too short") . fromList len +-- | Convert a list into vector, with length inferred. fromList' :: SingRep n => [a] -> Maybe (Vector a n) fromList' = fromList sing +-- | Unsafe version of 'unsafeFromList'. unsafeFromList' :: SingRep n => [a] -> Vector a n unsafeFromList' = unsafeFromList sing -all :: (a -> Bool) -> Vector a n -> Bool-all p = foldr ((&&) . p) False+-- | Convert a vector into a list.+toList :: Vector a n -> [a]+toList = foldr (:) [] -splitAt :: (n :<<= m) ~ True => SNat n -> Vector a m -> (Vector a n, Vector a (m :-: n))-splitAt SZ xs = (Nil, xs)-splitAt (SS n) (x :- xs) =- case splitAt n xs of- (xs', ys') -> (x :- xs', ys')-splitAt _ _ = error "could not happen!"+--------------------------------------------------+-- Basic Functions+-------------------------------------------------- -drop :: (n :<<= m) ~ True => SNat n -> Vector a m -> Vector a (m :-: n)-drop n = snd . splitAt n+-- | Append two @Vector@s.+append :: Vector a n -> Vector a m -> Vector a (n :+: m)+append (x :- xs) ys = x :- append xs ys+append Nil ys = ys +-- | Extract the first element of a non-empty vector.+head :: Vector a (S n) -> a+head (x :- _) = x++-- | Extract the last element of a non-empty vector.+last :: Vector a (S n) -> a+last (x :- Nil) = x+last (_ :- xs@(_ :- _)) = last xs++-- | Extract the elements after the head of a non-empty list.+tail :: Vector a (S n) -> Vector a n+tail (_ :- xs) = xs++-- | Test whether a @Vector@ is empty, though it's clear from the type parameter.+null :: Vector a n -> Bool+null Nil = True+null _ = False++-- | 'length' returns the length of a finite list as an 'Int'.+length :: Vector a n -> Int+length = sNatToInt . sLength++-- | 'sLength' returns the length of a finite list as a 'SNat' @n@.+sLength :: Vector a n -> SNat n+sLength Nil = sZ+sLength (_ :- xs) = sS $ sLength xs++--------------------------------------------------+-- Vector transformations+--------------------------------------------------++-- | 'map' @f xs@ is the vector obtained by applying @f@ to each element of xs.+map :: (a -> b) -> Vector a n -> Vector b n+map _ Nil = Nil+map f (x :- xs) = f x :- map f xs++-- | 'reverse' @xs@ returns the elements of xs in reverse order. @xs@ must be finite.+reverse :: forall a n. Vector a n -> Vector a n+reverse xs0 = case plusZR (sLength xs0) of Refl -> go Nil xs0+ where+ go :: Vector a m -> Vector a k -> Vector a (k :+ m)+ go acc Nil = acc+ go acc (x :- xs) = case plusSR (sLength xs) (sLength acc) of Refl -> go (x:- acc) xs+ +-- | The 'intersperse' function takes an element and a vector and+-- \`intersperses\' that element between the elements of the vector.+intersperse :: a -> Vector a n -> Vector a ((Two :* n) :- One)+intersperse _ Nil = Nil+intersperse a (x :- xs) = case plusSR (sLength xs) (sLength xs) of Refl -> x :- prependToAll a xs++prependToAll :: a -> Vector a n -> Vector a (Two :* n)+prependToAll _ Nil = Nil+prependToAll a (x :- xs) = case plusSR (sLength xs) (sLength xs) of Refl -> x :- a :- prependToAll a xs++-- | The 'transpose' function transposes the rows and columns of its argument.+transpose :: SingRep n => Vector (Vector a n) m -> Vector (Vector a m) n+transpose Nil = replicate' Nil+transpose (Nil :- _) = Nil+transpose ((x :- xs) :- xss) =+ case singInstance (sLength xs) of+ SingInstance -> (x :- map head xss) :- transpose (xs :- map tail xss)++--------------------------------------------------+-- Reducing vectors (folds)+--------------------------------------------------++-- | Left fold.+foldl :: (a -> b -> a) -> a -> Vector b n -> a+foldl _ a Nil = a+foldl f a (b :- bs) = foldl f (f a b) bs++-- | A strict version of 'foldl'.+foldl' :: forall a b n. (a -> b -> a) -> a -> Vector b n -> a+foldl' f z0 xs0 = lgo z0 xs0+ where+ lgo :: a -> Vector b m -> a+ lgo z Nil = z+ lgo z (x :- xs) = let z' = f z x in z' `seq` lgo z' xs++-- | Left fold for non-empty vector.+foldl1 :: (a -> a -> a) -> Vector a (S n) -> a+foldl1 f (a :- as) = foldl f a as++-- | A strict version of 'foldl1'.+foldl1' :: (a -> a -> a) -> Vector a (S n) -> a+foldl1' f (a :- as) = foldl' f a as++-- | Right fold.+foldr :: (a -> b -> b) -> b -> Vector a n -> b+foldr _ b Nil = b+foldr f a (x :- xs) = f x (foldr f a xs)++-- | Right fold for non-empty vector.+foldr1 :: (a -> a -> a) -> Vector a (S n) -> a+foldr1 _ (x :- Nil) = x+foldr1 f (x :- xs@(_ :- _)) = f x (foldr1 f xs)++-- | The function 'concat' concatenates all vectors in th vector.+concat :: Vector (Vector a n) m -> Vector a (m :*: n)+concat Nil = Nil+concat (xs :- xss) =+ let n = sLength xs+ n0 = sLength xss+ in case plusCommutative (n0 %* n) n of+ Refl -> xs `append` concat xss++and, or :: Vector Bool m -> Bool+-- | 'and' returns the conjunction of a Boolean vector.+and = foldr (&&) True++-- | 'or' returns the disjunction of a Boolean vector.+or = foldr (||) False++any, all :: (a -> Bool) -> Vector a n -> Bool+-- | Applied to a predicate and a list, 'any' determines if any element of the vector satisfies the predicate. +any p = or . map p+-- | Applied to a predicate and a list, 'all' determines if all element of the vector satisfies the predicate. +all p = and . map p++sum, product :: P.Num a => Vector a n -> a+sum = foldr (+) 0+product = foldr (*) 1++maximum, minimum :: P.Ord a => Vector a (S n) -> a+maximum = foldr1 P.max+minimum = foldr1 P.min++--------------------------------------------------+-- Subvectors+--------------------------------------------------++-- | 'take' @n xs@ returns the prefix of @xs@ of length @n@,+-- with @n@ less than or equal to the length of @xs@. take :: (n :<<= m) ~ True => SNat n -> Vector a m -> Vector a n take SZ _ = Nil take (SS n) (x :- xs) = x :- take n xs take _ _ = error "imposible!" +-- | A variant of @take@ which returns entire @xs@ if @n@ is greater than the length of @xs@. takeAtMost :: SNat n -> Vector a m -> Vector a (Min n m) takeAtMost = (fst .) . splitAtMost +-- | 'drop' @n xs@ returns the suffix of @xs@ after the first @n@ elements,+-- with @n@ less than or equal to the length of @xs@.+drop :: (n :<<= m) ~ True => SNat n -> Vector a m -> Vector a (m :-: n)+drop n = snd . splitAt n++-- | 'splitAt' @n xs@ returns a tuple where first element is @xs@ prefix of length @n@+-- and second element is the remainder of the list. @n@ should be less than or equal to the length of @xs@.+splitAt :: (n :<<= m) ~ True => SNat n -> Vector a m -> (Vector a n, Vector a (m :-: n))+splitAt SZ xs = (Nil, xs)+splitAt (SS n) (x :- xs) =+ case splitAt n xs of+ (xs', ys') -> (x :- xs', ys')+splitAt _ _ = error "could not happen!"++-- | A varian of 'splitAt' which allows @n@ to be greater than the length of @xs@. splitAtMost :: SNat n -> Vector a m -> (Vector a (Min n m), Vector a (m :-: n)) splitAtMost SZ Nil = (Nil, Nil) splitAtMost SZ (x :- xs) = (Nil, x :- xs)@@ -105,24 +298,121 @@ case splitAtMost n xs of (ys, zs) -> (x :- ys, zs) -map :: (a -> b) -> Vector a n -> Vector b n-map _ Nil = Nil-map f (x :- xs) = f x :- map f xs+-- | The 'stripPrefix' function drops the given prefix from a vector.+-- It returns @Nothing@ if the vector did not start with the prefix given or shorter than the prefix,+-- or Just the vector after the prefix, if it does.+stripPrefix :: Eq a => Vector a n -> Vector a m -> Maybe (Vector a (m :- n))+stripPrefix Nil ys = Just ys+stripPrefix (_ :- _) Nil = Nothing+stripPrefix (x :- xs) (y :- ys)+ | x == y = stripPrefix xs ys+ | otherwise = Nothing -head :: Vector a (S n) -> a-head (x :- _) = x+--------------------------------------------------+-- Searching vectors+-------------------------------------------------- -tail :: Vector a (S n) -> Vector a n-tail (_ :- xs) = xs+elem, notElem :: Eq a => a -> Vector a n -> Bool+elem a = any (== a)+notElem a = all (/= a) +find :: (a -> Bool) -> Vector a n -> Maybe a+find _ Nil = Nothing+find p (x :- xs)+ | p x = Just x+ | otherwise = find p xs++--------------------------------------------------+-- Indexing vectors+--------------------------------------------------++-- | List index (subscript) operator, starting from @sZero@.+(!!) :: ((n :<<= m) ~ True) => Vector a (S m) -> SNat n -> a+(!!) = flip index++-- | A 'Index' version of '!!'.+(%!!) :: Vector a n -> Index n -> a+(%!!) = flip sIndex++-- | Flipped version of '!!'. index :: ((n :<<= m) ~ True) => SNat n -> Vector a (S m) -> a index SZ (a :- _) = a index (SS n) (_ :- (a :- as)) = index n (a :- as) -instance Monomorphicable (Vector a) where- type MonomorphicRep (Vector a) = [a]- demote (Monomorphic vec) = toList vec- promote [] = Monomorphic Nil- promote (x:xs) =- case promote xs of- Monomorphic vec -> Monomorphic $ x :- vec+-- | A 'Index' version of 'index'.+sIndex :: Index n -> Vector a n -> a+sIndex (Index SZ) (x :- _) = x+sIndex (Index (SS n)) (_ :- xs) = sIndex (Index n) xs++-- | The 'elemIndex' function returns the index (as 'Int') of the first element in the given list+-- which is equal (by '==') to the query element, or Nothing if there is no such element.+elemIndex :: Eq a => a -> Vector a n -> Maybe Int+elemIndex a = findIndex (== a)++-- | 'Index' version of 'elemIndex'.+sElemIndex :: Eq a => a -> Vector a n -> Maybe (Index n)+sElemIndex a = sFindIndex (== a)++-- | The 'elemIndices' function extends 'elemIndex', by returning the indices of all elements equal to the query element,+-- in ascending order.+elemIndices :: Eq a => a -> Vector a n -> [Int]+elemIndices a = findIndices (== a)++-- | 'Index' version of 'elemIndices'.+sElemIndices :: Eq a => a -> Vector a n -> [Index n]+sElemIndices a = sFindIndices (== a)++-- | The findIndex function takes a predicate and a vector+-- and returns the index of the first element in the vector+-- satisfying the predicate, or Nothing if there is no such element.+findIndex :: (a -> Bool) -> Vector a n -> Maybe Int+findIndex p = listToMaybe . findIndices p++-- | 'Index' version of 'findIndex'.+sFindIndex :: (a -> Bool) -> Vector a n -> Maybe (Index n)+sFindIndex p = listToMaybe . sFindIndices p++-- | The 'findIndices' function extends 'findIndex', by returning the indices of all elements satisfying the predicate,+-- in ascending order.+findIndices :: (a -> Bool) -> Vector a n -> [Int]+findIndices p = P.map indexToInt . sFindIndices p++-- | 'Index' version of 'findIndices'.+sFindIndices :: (a -> Bool) -> Vector a n -> [Index n]+sFindIndices _ Nil = []+sFindIndices p (x :- xs)+ | p x = Index sZero : P.map succIndex (sFindIndices p xs)+ | otherwise = P.map succIndex $ sFindIndices p xs++--------------------------------------------------+-- Zipping vectors+--------------------------------------------------++-- | 'zip' takes two vectors and returns a vector of corresponding pairs.+-- If one input list is short, excess elements of the longer list are discarded.+zip :: Vector a n -> Vector b m -> Vector (a, b) (Min n m)+zip = zipWith (,)++-- | Same as 'zip', but the given vectors must have the same length.+zipSame :: Vector a n -> Vector b n -> Vector (a, b) n+zipSame = zipWithSame (,)++-- | 'zipWith' generalises 'zip' by zipping with the function given as the first argument, instead of a tupling function.+zipWith :: (a -> b -> c) -> Vector a n -> Vector b m -> Vector c (Min n m)+zipWith _ Nil Nil = Nil+zipWith _ Nil (_ :- _) = Nil+zipWith _ (_ :- _) Nil = Nil+zipWith f (x :- xs) (y :- ys) = f x y :- zipWith f xs ys++-- | Same as 'zipWith', but the given vectors must have the same length.+zipWithSame :: (a -> b -> c) -> Vector a n -> Vector b n -> Vector c n+zipWithSame _ Nil Nil = Nil+zipWithSame f (x :- xs) (y :- ys) = f x y :- zipWithSame f xs ys+zipWithSame _ _ _ = error "cannot happen"++-- | Inverse of 'zipSame'.+unzip :: Vector (a, b) n -> (Vector a n, Vector b n)+unzip Nil = (Nil, Nil)+unzip ((a, b) :- ps) =+ let (as, bs) = unzip ps+ in (a :- as, b :- bs)
sized-vector.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: sized-vector-version: 0.0.2.5+version: 1.0.0.0 synopsis: Size-parameterized vector types and functions. description: Size-parameterized vector types and functions using a data-type promotion. homepage: https://github.com/konn/sized-vector@@ -21,7 +21,8 @@ library exposed-modules: Data.Vector.Sized- build-depends: base >= 2.0 && < 5- , singletons == 0.8.*- , type-natural >= 0.0.2.0- , monomorphic == 0.0.*+ build-depends: base >= 2.0 && < 5+ , singletons == 0.8.*+ , type-natural >= 0.0.2.0+ , monomorphic == 0.0.*+ , equational-reasoning == 0.0.*