clash-0.1.2.2: Data/Param/Vector.hs
{-# LANGUAGE TemplateHaskell, ExistentialQuantification, TypeOperators, TypeFamilies, ScopedTypeVariables #-}
module Data.Param.Vector
( Vector
, empty
, (+>)
, singleton
, vTH
, unsafeVector
, readVector
, vlength
, vlengthT
, fromVector
, vnull
, (!)
, vreplace
, vhead
, vlast
, vinit
, vtail
, vtake
, vdrop
, vselect
, (<+)
, (<++>)
, vmap
, vzipWith
, vfoldl
, vfoldr
, vzip
, vunzip
, (+>>)
, (<<+)
, vrotl
, vrotr
, vconcat
, vreverse
, viterate
, viteraten
, vgenerate
, vgeneraten
, vcopy
, vcopyn
, vsplit
) where
import Types
import Types.Data.Num
import Types.Data.Num.Decimal.Literals.TH
import Data.Param.Index
import Data.Typeable
import qualified Data.Foldable as DF
import qualified Data.Traversable as DT
import Language.Haskell.TH hiding (Pred)
import Language.Haskell.TH.Syntax (Lift(..))
newtype (NaturalT s) => Vector s a = Vector {unVec :: [a]}
deriving Eq
-- ==========================
-- = Constructing functions =
-- ==========================
empty :: Vector D0 a
empty = Vector []
(+>) :: a -> Vector s a -> Vector (Succ s) a
x +> (Vector xs) = Vector (x:xs)
infix 5 +>
singleton :: a -> Vector D1 a
singleton x = x +> empty
-- FIXME: Not the most elegant solution... but it works for now in clash
vTH :: (Lift a) => [a] -> ExpQ
-- vectorTH xs = sigE [| (TFVec xs) |] (decTFVecT (toInteger (P.length xs)) xs)
vTH [] = [| empty |]
vTH [x] = [| singleton x |]
vTH (x:xs) = [| x +> $(vTH xs) |]
unsafeVector :: NaturalT s => s -> [a] -> Vector s a
unsafeVector l xs
| fromIntegerT l /= length xs =
error (show 'unsafeVector ++ ": dynamic/static lenght mismatch")
| otherwise = Vector xs
readVector :: (Read a, NaturalT s) => String -> Vector s a
readVector = read
-- =======================
-- = Observing functions =
-- =======================
vlength :: forall s a . NaturalT s => Vector s a -> Int
vlength _ = fromIntegerT (undefined :: s)
vlengthT :: NaturalT s => Vector s a -> s
vlengthT = undefined
fromVector :: NaturalT s => Vector s a -> [a]
fromVector (Vector xs) = xs
vnull :: Vector D0 a -> Bool
vnull _ = True
(!) :: PositiveT s => Vector s a -> Index s -> a
(Vector xs) ! i = xs !! (fromInteger (toInteger i))
-- ==========================
-- = Transforming functions =
-- ==========================
vreplace :: PositiveT s =>
Vector s a -> Index s -> a -> Vector s a
vreplace (Vector xs) i y = Vector $ replace' xs (toInteger i) y
where replace' [] _ _ = []
replace' (_:xs) 0 y = (y:xs)
replace' (x:xs) n y = x : (replace' xs (n-1) y)
vhead :: PositiveT s => Vector s a -> a
vhead = head . unVec
vtail :: PositiveT s => Vector s a -> Vector (Pred s) a
vtail = liftV tail
vlast :: PositiveT s => Vector s a -> a
vlast = last . unVec
vinit :: PositiveT s => Vector s a -> Vector (Pred s) a
vinit = liftV init
vtake :: NaturalT i => i -> Vector s a -> Vector (Min s i) a
vtake i = liftV $ take (fromIntegerT i)
vdrop :: NaturalT i => i -> Vector s a -> Vector (s :-: (Min s i)) a
vdrop i = liftV $ drop (fromIntegerT i)
vselect :: (NaturalT f, NaturalT s, NaturalT n, (f :<: i) ~ True,
(((s :*: n) :+: f) :<=: i) ~ True) =>
f -> s -> n -> Vector i a -> Vector n a
vselect f s n = liftV (select' f' s' n')
where (f', s', n') = (fromIntegerT f, fromIntegerT s, fromIntegerT n)
select' f s n = ((selectFirst0 s n).(drop f))
selectFirst0 :: Int -> Int -> [a] -> [a]
selectFirst0 s n l@(x:_)
| n > 0 = x : selectFirst0 s (n-1) (drop s l)
| otherwise = []
selectFirst0 _ 0 [] = []
(<+) :: Vector s a -> a -> Vector (Succ s) a
(<+) (Vector xs) x = Vector (xs ++ [x])
(<++>) :: Vector s a -> Vector s2 a -> Vector (s :+: s2) a
(<++>) = liftV2 (++)
infixl 5 <+
infixr 5 <++>
vmap :: (a -> b) -> Vector s a -> Vector s b
vmap f = liftV (map f)
vzipWith :: ((s :>=: s') ~ True) => (a -> b -> c) -> Vector s a -> Vector s' b -> Vector s' c
vzipWith f = liftV2 (zipWith f)
vfoldl :: (a -> b -> a) -> a -> Vector s b -> a
vfoldl f e = (foldl f e) . unVec
vfoldr :: (b -> a -> a) -> a -> Vector s b -> a
vfoldr f e = (foldr f e) . unVec
vzip :: Vector s a -> Vector s b -> Vector s (a, b)
vzip = liftV2 zip
vunzip :: Vector s (a, b) -> (Vector s a, Vector s b)
vunzip (Vector xs) = let (a,b) = unzip xs in (Vector a, Vector b)
(+>>) :: (PositiveT s, NaturalT n, n ~ Pred s, s ~ Succ n) =>
a -> Vector s a -> Vector s a
x +>> xs = x +> vinit xs
(<<+) :: (PositiveT s, NaturalT n, n ~ Pred s, s ~ Succ n) =>
Vector s a -> a -> Vector s a
xs <<+ x = vtail xs <+ x
vrotl :: forall s a . NaturalT s => Vector s a -> Vector s a
vrotl = liftV rotl'
where vlen = fromIntegerT (undefined :: s)
rotl' [] = []
rotl' xs = let (i,[l]) = splitAt (vlen - 1) xs
in l : i
vrotr :: NaturalT s => Vector s a -> Vector s a
vrotr = liftV rotr'
where
rotr' [] = []
rotr' (x:xs) = xs ++ [x]
vconcat :: Vector s1 (Vector s2 a) -> Vector (s1 :*: s2) a
vconcat = liftV (foldr ((++).unVec) [])
vreverse :: Vector s a -> Vector s a
vreverse = liftV reverse
viterate :: NaturalT s => (a -> a) -> a -> Vector s a
viterate = viteraten (undefined :: s)
viteraten :: NaturalT s => s -> (a -> a) -> a -> Vector s a
viteraten s f x = let s' = fromIntegerT s in Vector (take s' $ iterate f x)
vgenerate :: NaturalT s => (a -> a) -> a -> Vector s a
vgenerate = vgeneraten (undefined :: s)
vgeneraten :: NaturalT s => s -> (a -> a) -> a -> Vector s a
vgeneraten s f x = let s' = fromIntegerT s in Vector (take s' $ tail $ iterate f x)
vcopy :: NaturalT s => a -> Vector s a
vcopy x = vcopyn (undefined :: s) x
vcopyn :: NaturalT s => s -> a -> Vector s a
vcopyn s x = viteraten s id x
vsplit :: ( NaturalT s
-- , IsEven s ~ True
) => Vector s a -> (Vector (Div2 s) a, Vector (Div2 s) a)
vsplit (Vector xs) = (Vector (take vlen xs), Vector (drop vlen xs))
where
vlen = round ((fromIntegral (length xs)) / 2)
-- =============
-- = Instances =
-- =============
instance Show a => Show (Vector s a) where
showsPrec _ = showV.unVec
where showV [] = showString "<>"
showV (x:xs) = showChar '<' . shows x . showl xs
where showl [] = showChar '>'
showl (x:xs) = showChar ',' . shows x .
showl xs
instance (Read a, NaturalT nT) => Read (Vector nT a) where
readsPrec _ str
| all fitsLength possibilities = map toReadS possibilities
| otherwise = error (fName ++ ": string/dynamic length mismatch")
where
fName = "Data.Param.TFVec.read"
expectedL = fromIntegerT (undefined :: nT)
possibilities = readVectorList str
fitsLength (_, l, _) = l == expectedL
toReadS (xs, _, rest) = (Vector xs, rest)
instance NaturalT s => DF.Foldable (Vector s) where
foldr = vfoldr
instance NaturalT s => Functor (Vector s) where
fmap = vmap
instance NaturalT s => DT.Traversable (Vector s) where
traverse f = (fmap Vector).(DT.traverse f).unVec
instance (Lift a, NaturalT nT) => Lift (Vector nT a) where
lift (Vector xs) = [| unsafeVectorCoerse
$(decLiteralV (fromIntegerT (undefined :: nT)))
(Vector xs) |]
-- ======================
-- = Internal Functions =
-- ======================
liftV :: ([a] -> [b]) -> Vector nT a -> Vector nT' b
liftV f = Vector . f . unVec
liftV2 :: ([a] -> [b] -> [c]) -> Vector s a -> Vector s2 b -> Vector s3 c
liftV2 f a b = Vector (f (unVec a) (unVec b))
splitAtM :: Int -> [a] -> Maybe ([a],[a])
splitAtM n xs = splitAtM' n [] xs
where splitAtM' 0 xs ys = Just (xs, ys)
splitAtM' n xs (y:ys) | n > 0 = do
(ls, rs) <- splitAtM' (n-1) xs ys
return (y:ls,rs)
splitAtM' _ _ _ = Nothing
unsafeVectorCoerse :: nT' -> Vector nT a -> Vector nT' a
unsafeVectorCoerse _ (Vector v) = (Vector v)
readVectorList :: Read a => String -> [([a], Int, String)]
readVectorList = readParen' False (\r -> [pr | ("<",s) <- lexVector r,
pr <- readl s])
where
readl s = [([],0,t) | (">",t) <- lexVector s] ++
[(x:xs,1+n,u) | (x,t) <- reads s,
(xs, n, u) <- readl' t]
readl' s = [([],0,t) | (">",t) <- lexVector s] ++
[(x:xs,1+n,v) | (",",t) <- lex s,
(x,u) <- reads t,
(xs,n,v) <- readl' u]
readParen' b g = if b then mandatory else optional
where optional r = g r ++ mandatory r
mandatory r = [(x,n,u) | ("(",s) <- lexVector r,
(x,n,t) <- optional s,
(")",u) <- lexVector t]
-- Custom lexer for FSVecs, we cannot use lex directly because it considers
-- sequences of < and > as unique lexemes, and that breaks nested FSVecs, e.g.
-- <<1,2><3,4>>
lexVector :: ReadS String
lexVector ('>':rest) = [(">",rest)]
lexVector ('<':rest) = [("<",rest)]
lexVector str = lex str