-- | A very simple library for manipulating continuous signals. module Signal ( Time -- | the 'Signal' type is abstract , Signal -- * Smart constructors , constS, timeS -- * Combinators , ($$), mapT -- * Derived operation , mapS -- * Run function , sample ) where import Control.Monad (forM_) import Control.Applicative(Applicative(pure,(<*>)),(<$>),liftA2) -- * Smart constructors constS :: a -> Signal a timeS :: Signal Time -- * Combinators ($$) :: Signal (a -> b) -> Signal a -> Signal b mapT :: (Time -> Time) -> Signal a -> Signal a -- * Derived operation mapS :: (a -> b) -> Signal a -> Signal b -- * Run function sample :: Signal a -> Time -> a type Time = Double newtype Signal a = Sig {unSig :: Time -> a} -- | The constant signal. constS x = Sig (const x) -- | The time signal timeS = Sig id -- | Function application lifted to signals. fs $$ xs = Sig (\t -> unSig fs t (unSig xs t)) -- | Mapping a function over a signal. mapS f xs = constS f $$ xs -- | Transforming the time. mapT f xs = Sig (unSig xs . f) -- | Sampling a signal at a given time point. -- This is the /semantic function/ of our library. sample = unSig -------------------------------------------- -- Examples -- | sinusoidal of given frequency sinS :: Double -> Signal Double sinS freq = mapT (freq*) $ mapS sin timeS test1 :: IO () test1 = magic $ sinS 0.1 -- | Problem: averaging two signals? -- @ -- averageS :: Fractional a => -- Signal a -> Signal a -> Signal a -- averageS = -- ... Fill in a definition here ... -- @ -- Hint: use the average function, mapS and $$ combinators. average :: Fractional a => a -> a -> a average x y = (x + y) / 2.0 scale :: Num a => Signal a -> Signal a scale = mapS ((30*) . (1+)) -- | Discretize a signal discretize :: Signal Double -> Signal Int discretize = mapS round -- | convert to "analog" toBars :: Signal Int -> Signal String toBars = mapS (`replicate` '#') displayLength = 100 -- | display the signal at a number of points display :: Signal String -> IO () display ss = forM_ [0..displayLength] $ \x -> putStrLn (sample ss x) -- | The display magic. -- Note how we take advantage of function composition, -- types defined so far, etc. magic :: Signal Double -> IO () magic = display . toBars . discretize . scale -- | Signal is an applicative functor instance Functor Signal where fmap = mapS instance Applicative Signal where pure = constS (<*>) = ($$) ---------------------------------------------------- -- | Answer to exercise averageS :: Fractional a => Signal a -> Signal a -> Signal a averageS xs ys = mapS average xs $$ ys -- | It can also be generalised to an arbitray Applicative functor averageA :: (Fractional a, Applicative f) => f a -> f a -> f a averageA xs ys = average <$> xs <*> ys -- | or slightly shorter averageA' :: (Fractional a, Applicative f) => f a -> f a -> f a averageA' = liftA2 average -- | Control.Applicative: --