packages feed

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