packages feed

signals-0.2.0.1: src/Signal/Core.hs

{-# LANGUAGE GADTs                 #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances  #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE ScopedTypeVariables   #-}

module Signal.Core
  ( Sig   (..)
  , Signal(..)
  , Symbol(..)
  , S     (..)
  , E    
  , variable

    -- ^ ...
  , delay
  , mux
  , lift
    
    -- ^ ...
  , mux2
  , lift0
  , lift1
  , lift2
  ) where

import Signal.Core.Witness

import Control.Monad.Operational.Higher hiding (join)
import Control.Monad.Identity           hiding (join)
import Data.Bits
import Data.Typeable          (Typeable)
import Data.Dynamic           (Dynamic)
import Data.Ref
import Data.Unique

import Language.Embedded.VHDL.Interface

import Prelude hiding (Left, Right, map, repeat)
import qualified Prelude as P

--------------------------------------------------------------------------------
-- * Signals
--------------------------------------------------------------------------------

-- | ...
newtype Sig    i a = Sig { runSig :: Signal i (Identity a) }

-- | ...
newtype Signal i a = Signal { runSignal :: Symbol i a }

-- | ...
newtype Symbol i a = Symbol (Ref (S Symbol i a))

-- | ...
data S sig i a
  where
    -- ^ Constant signals
    Repeat :: (Typeable a, PredicateExp (IExp i) a) => IExp i a -> S sig i (Identity a)

    -- ^ Signal transformers
    Map    :: (Witness i a, Witness i b) => (E i a -> E i b) -> sig i a -> S sig i b

    -- ^ Wiring operators
    Join   :: (Witness i a, Witness i b) => sig i a -> sig i b -> S sig i (a, b)
    Left   :: (Witness i a, Witness i b) => sig i (a, b) -> S sig i a
    Right  :: (Witness i a, Witness i b) => sig i (a, b) -> S sig i b

    -- ^ Registers
    Delay  :: (Typeable a, PredicateExp (IExp i) a)
           => IExp i a
           -> sig i (Identity a)
           -> S sig i (Identity a)

    -- ^ Multiplexers
    Mux    :: (Typeable a, PredicateExp (IExp i) a, Witness i b)
           => sig i (Identity a)
           -> [(a, sig i b)]
           -> S sig i b

    -- ^ Variable trick
    Var    :: Witness i a => Dynamic -> S sig i a

-- | Type for nested tuples, stripping away all Identity
type family E i a
  where
    E i (Identity a) = IExp i a
    E i (a, b)       = (E i a, E i b)

--------------------------------------------------------------------------------
-- ** Some `smart` constructions

signal :: S Symbol i a -> Signal i a
signal = Signal . symbol

symbol :: S Symbol i a -> Symbol i a
symbol = Symbol . ref

unsymbol :: Symbol i a -> S Symbol i a
unsymbol (Symbol s) = deref s

--------------------------------------------------------------------------------
-- internal

repeat :: (Typeable a, PredicateExp (IExp i) a) => IExp i a -> Signal i (Identity a)
repeat s = signal $ Repeat s

map :: (Witness i a, Witness i b) => (E i a -> E i b) -> Signal i a -> Signal i b
map f (Signal s) = signal $ Map f s

join :: (Witness i a, Witness i b) => Signal i a -> Signal i b -> Signal i (a, b)
join (Signal a) (Signal b) = signal $ Join a b

left :: (Witness i a, Witness i b) => Signal i (a, b) -> Signal i a
left (Signal s) = signal $ Left s

right :: (Witness i a, Witness i b) => Signal i (a, b) -> Signal i b
right (Signal s) = signal $ Right s

variable :: Witness i a => Dynamic -> Signal i a
variable = signal . Var 

--------------------------------------------------------------------------------
-- user

-- | Delay a signal by one instant, returning the given value in the first instant
delay :: (Typeable a, PredicateExp (IExp i) a) => IExp i a -> Sig i a -> Sig i a
delay e (Sig (Signal s)) = Sig . signal $ Delay e s

-- | Choose output signal according to a control signal
--
-- ^ List must be total, covering all cases
-- ^ ...
mux :: ( Typeable a, PredicateExp (IExp i) a
       , Typeable b, PredicateExp (IExp i) b)
    => Sig i a
    -> [(a, Sig i b)]
    -> Sig i b
mux (Sig (Signal s)) = Sig . signal . Mux s . fmap (fmap (runSignal . runSig))

--------------------------------------------------------------------------------
-- ** Properties of signals

instance Eq (Sig i a)
  where
    Sig (Signal (Symbol s1)) == Sig (Signal (Symbol s2)) = s1 == s2

instance (Bounded (IExp i a), Typeable a, PredicateExp (IExp i) a) => Bounded (Sig i a)
  where
    minBound = lift0 minBound
    maxBound = lift0 maxBound

instance (Ord (IExp i a), Typeable a, PredicateExp (IExp i) a) => Ord (Sig i a)
  where
    compare = error "compare is not suppored"
    max     = lift2 max
    min     = lift2 min

instance (Enum (IExp i a), Typeable a, PredicateExp (IExp i) a) => Enum (Sig i a) -- needed for integral
  where
    toEnum   = error "toEnum not supported"
    fromEnum = error "fromEnum not supported"

instance (Bits (IExp i a), Typeable a, PredicateExp (IExp i) a) => Bits (Sig i a)
  where
    (.&.)        = lift2 (.&.)
    (.|.)        = lift2 (.|.)
    xor          = lift2 xor
    complement   = lift1 complement 
    shift  s n   = lift1 (flip shift n) s
    rotate s n   = lift1 (flip rotate n) s
    bit          = lift0 . bit
    testBit      = error "testBit is not supported.. yet"
    bitSize      = error "bitSize is not supported.. yet"
    bitSizeMaybe = error "bitSizeMaybe is not supported.. yet"
    isSigned     = error "isSigned is not supported.. yet"
    popCount     = error "popCound is not supported.. yet"
    
instance (Num (IExp i a), Typeable a, PredicateExp (IExp i) a) => Num (Sig i a)
  where
    (+)         = lift2 (+)
    (-)         = lift2 (-)
    (*)         = lift2 (*)
    negate      = lift1 negate
    abs         = lift1 abs
    signum      = lift1 signum
    fromInteger = lift0 . fromInteger

instance (Fractional (IExp i a), Typeable a, PredicateExp (IExp i) a) => Fractional (Sig i a)
  where
    (/)          = lift2 (/)
    recip        = lift1 recip
    fromRational = lift0 . fromRational

instance (Real (IExp i a), Typeable a, PredicateExp (IExp i) a) => Real (Sig i a)
  where
    toRational = error "toRational not supported"

instance (Integral (IExp i a), Typeable a, PredicateExp (IExp i) a) => Integral (Sig i a)
  where
    quot      = lift2 quot
    rem       = lift2 rem
    quotRem   = curry $ lift p $ uncurry quotRem
      where p = undefined :: proxy i (Identity a, Identity a) (Identity a, Identity a)
    toInteger = error "toIntegral not supported"

--------------------------------------------------------------------------------
-- * Nested Signals
--------------------------------------------------------------------------------

-- | Type for nested tuples of signals
type family Packed (i :: (* -> *) -> * -> *) a :: *
type instance Packed i (Identity a) = Sig i a
type instance Packed i (a, b)       = (Packed i a, Packed i b)

pack :: forall i a. Witness i a => Signal i a -> Packed i a
pack s = go (witness :: Wit i a) s
  where
    go :: Wit i x -> Signal i x -> Packed i x
    go (WE)     s = Sig s
    go (WP u v) s = (,) (go u $ left s) (go v $ right s)

unpack :: forall i a. Witness i a => Packed i a -> Signal i a
unpack s = go (witness :: Wit i a) s
  where
    go :: Wit i x -> Packed i x -> Signal i x
    go (WE)     (Sig s) = s
    go (WP u v) (l, r)  = join (go u l) (go v r)

--------------------------------------------------------------------------------
-- ** General lifting operator

-- todo: I don't like the proxy, or the type family. Possible to find E^(-1)?
--     : can use injective type functions to get rid of proxy.
lift 
  :: forall proxy i a b. (Witness i a, Witness i b)
  => proxy i a b
  -> (E i a      -> E i b)
  -> (Packed i a -> Packed i b)
lift _ f = pack . (map f :: Signal i a -> Signal i b) . unpack

--------------------------------------------------------------------------------
-- * Some common signal operations
--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- ** Multiplexing

mux2
  :: ( Typeable a
     , PredicateExp (IExp i) a
     , PredicateExp (IExp i) Bool)
  => Sig i Bool
  -> (Sig i a, Sig i a)
  -> Sig i a
mux2 b (t, f) = mux b [(True, t), (False, f)]

--------------------------------------------------------------------------------
-- ** Lifting

lift0 :: (Typeable a, PredicateExp e a, e ~ IExp i) => e a -> Sig i a
lift0 = Sig . repeat

lift1
  :: forall i e a b.
     ( Typeable a, PredicateExp e a
     , Typeable b, PredicateExp e b
     , e ~ IExp i)
  => (e a -> e b)
  -> Sig i a
  -> Sig i b
lift1 f = lift p f
  where
    p = undefined :: proxy i (Identity a) (Identity b)

lift2
  :: forall i e a b c.
     ( Typeable a, PredicateExp e a
     , Typeable b, PredicateExp e b
     , Typeable c, PredicateExp e c
     , e ~ IExp i)
  => (e a -> e b -> e c)
  -> Sig i a
  -> Sig i b
  -> Sig i c
lift2 f = curry $ lift p $ uncurry f
  where
    p = undefined :: proxy i (Identity a, Identity b) (Identity c)

--------------------------------------------------------------------------------
-- the end.