{- |
  A design study about how to design signal processors
  that adapt to a common sample rate.
  I simplified "Synthesizer.Inference.DesignStudy.Arrow" to this module
  which uses only Applicative functors.
-}
module Synthesizer.Inference.DesignStudy.Applicative where

import Data.List (intersect)
import Control.Applicative (Applicative(..), liftA3, )

data Rates = Rates [Int] | Any deriving Show
-- it is a Reader monad with context processing
data Processor a = P Rates (Rates -> a)

intersectRates :: Rates -> Rates -> Rates
intersectRates Any y = y
intersectRates x Any = x
intersectRates (Rates xs) (Rates ys) = Rates $ intersect xs ys

instance Functor Processor where
   fmap f (P r f0) = P r (f . f0)

instance Applicative Processor where
   pure x = P Any (const x)
   (P r0 f0) <*> (P r1 f1)  =
      P (intersectRates r0 r1) (\r -> f0 r (f1 r))

runProcessor :: Processor a -> a
runProcessor (P r f) = f r

-- test processors
processor1, processor2, processor3 :: Processor Rates
processor1 = P (Rates [44100, 48000]) id
processor2 = P Any                    id
processor3 = P (Rates [48000])        id

process :: Processor (Rates, Rates, Rates)
process = liftA3 (,,) processor1 processor2 processor3

test :: (Rates, Rates, Rates)
test = runProcessor process