{-# LANGUAGE UndecidableInstances #-}

module Blucontrol.Monad.Gamma.Modifier (
  GammaModifierT
, runGammaModifierT
) where

import Control.Monad.Base
import Control.Monad.Except
import Control.Monad.Reader
import Control.Monad.Trans.Control

import Blucontrol.Monad.Gamma

newtype GammaModifierT m a = GammaModifierT { GammaModifierT m a
-> ReaderT (GammaValue m -> IO (GammaValue m)) m a
unGammaModifierT :: ReaderT (GammaValue m -> IO (GammaValue m)) m a }
  deriving (Functor (GammaModifierT m)
a -> GammaModifierT m a
Functor (GammaModifierT m)
-> (forall a. a -> GammaModifierT m a)
-> (forall a b.
    GammaModifierT m (a -> b)
    -> GammaModifierT m a -> GammaModifierT m b)
-> (forall a b c.
    (a -> b -> c)
    -> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c)
-> (forall a b.
    GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b)
-> (forall a b.
    GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a)
-> Applicative (GammaModifierT m)
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a
GammaModifierT m (a -> b)
-> GammaModifierT m a -> GammaModifierT m b
(a -> b -> c)
-> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c
forall a. a -> GammaModifierT m a
forall a b.
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a
forall a b.
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
forall a b.
GammaModifierT m (a -> b)
-> GammaModifierT m a -> GammaModifierT m b
forall a b c.
(a -> b -> c)
-> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall (m :: * -> *). Applicative m => Functor (GammaModifierT m)
forall (m :: * -> *) a. Applicative m => a -> GammaModifierT m a
forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a
forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m (a -> b)
-> GammaModifierT m a -> GammaModifierT m b
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c
<* :: GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a
$c<* :: forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m a
*> :: GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
$c*> :: forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
liftA2 :: (a -> b -> c)
-> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c
$cliftA2 :: forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m c
<*> :: GammaModifierT m (a -> b)
-> GammaModifierT m a -> GammaModifierT m b
$c<*> :: forall (m :: * -> *) a b.
Applicative m =>
GammaModifierT m (a -> b)
-> GammaModifierT m a -> GammaModifierT m b
pure :: a -> GammaModifierT m a
$cpure :: forall (m :: * -> *) a. Applicative m => a -> GammaModifierT m a
$cp1Applicative :: forall (m :: * -> *). Applicative m => Functor (GammaModifierT m)
Applicative, a -> GammaModifierT m b -> GammaModifierT m a
(a -> b) -> GammaModifierT m a -> GammaModifierT m b
(forall a b. (a -> b) -> GammaModifierT m a -> GammaModifierT m b)
-> (forall a b. a -> GammaModifierT m b -> GammaModifierT m a)
-> Functor (GammaModifierT m)
forall a b. a -> GammaModifierT m b -> GammaModifierT m a
forall a b. (a -> b) -> GammaModifierT m a -> GammaModifierT m b
forall (m :: * -> *) a b.
Functor m =>
a -> GammaModifierT m b -> GammaModifierT m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> GammaModifierT m a -> GammaModifierT m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: a -> GammaModifierT m b -> GammaModifierT m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> GammaModifierT m b -> GammaModifierT m a
fmap :: (a -> b) -> GammaModifierT m a -> GammaModifierT m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> GammaModifierT m a -> GammaModifierT m b
Functor, Applicative (GammaModifierT m)
a -> GammaModifierT m a
Applicative (GammaModifierT m)
-> (forall a b.
    GammaModifierT m a
    -> (a -> GammaModifierT m b) -> GammaModifierT m b)
-> (forall a b.
    GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b)
-> (forall a. a -> GammaModifierT m a)
-> Monad (GammaModifierT m)
GammaModifierT m a
-> (a -> GammaModifierT m b) -> GammaModifierT m b
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
forall a. a -> GammaModifierT m a
forall a b.
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
forall a b.
GammaModifierT m a
-> (a -> GammaModifierT m b) -> GammaModifierT m b
forall (m :: * -> *). Monad m => Applicative (GammaModifierT m)
forall (m :: * -> *) a. Monad m => a -> GammaModifierT m a
forall (m :: * -> *) a b.
Monad m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
forall (m :: * -> *) a b.
Monad m =>
GammaModifierT m a
-> (a -> GammaModifierT m b) -> GammaModifierT m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: a -> GammaModifierT m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> GammaModifierT m a
>> :: GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
GammaModifierT m a -> GammaModifierT m b -> GammaModifierT m b
>>= :: GammaModifierT m a
-> (a -> GammaModifierT m b) -> GammaModifierT m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
GammaModifierT m a
-> (a -> GammaModifierT m b) -> GammaModifierT m b
$cp1Monad :: forall (m :: * -> *). Monad m => Applicative (GammaModifierT m)
Monad, MonadBase b, MonadBaseControl b)
-- TODO: A `MonadTransControl` instance seems to be impossible

instance MonadTrans GammaModifierT where
  lift :: m a -> GammaModifierT m a
lift = ReaderT (GammaValue m -> IO (GammaValue m)) m a
-> GammaModifierT m a
forall (m :: * -> *) a.
ReaderT (GammaValue m -> IO (GammaValue m)) m a
-> GammaModifierT m a
GammaModifierT (ReaderT (GammaValue m -> IO (GammaValue m)) m a
 -> GammaModifierT m a)
-> (m a -> ReaderT (GammaValue m -> IO (GammaValue m)) m a)
-> m a
-> GammaModifierT m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> ReaderT (GammaValue m -> IO (GammaValue m)) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift

instance (MonadBase IO m, MonadGamma m) => MonadGamma (GammaModifierT m) where
  type GammaValue (GammaModifierT m) = GammaValue m
  gamma :: GammaModifierT m (GammaValue (GammaModifierT m))
gamma = do GammaValue m
oldGamma <- m (GammaValue m) -> GammaModifierT m (GammaValue m)
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m (GammaValue m)
forall (m :: * -> *). MonadGamma m => m (GammaValue m)
gamma
             GammaValue m -> IO (GammaValue m)
modifyGamma <- ReaderT
  (GammaValue m -> IO (GammaValue m))
  m
  (GammaValue m -> IO (GammaValue m))
-> GammaModifierT m (GammaValue m -> IO (GammaValue m))
forall (m :: * -> *) a.
ReaderT (GammaValue m -> IO (GammaValue m)) m a
-> GammaModifierT m a
GammaModifierT ReaderT
  (GammaValue m -> IO (GammaValue m))
  m
  (GammaValue m -> IO (GammaValue m))
forall r (m :: * -> *). MonadReader r m => m r
ask
             IO (GammaValue m) -> GammaModifierT m (GammaValue m)
forall (b :: * -> *) (m :: * -> *) α. MonadBase b m => b α -> m α
liftBase (IO (GammaValue m) -> GammaModifierT m (GammaValue m))
-> IO (GammaValue m) -> GammaModifierT m (GammaValue m)
forall a b. (a -> b) -> a -> b
$ GammaValue m -> IO (GammaValue m)
modifyGamma GammaValue m
oldGamma

runGammaModifierT :: (GammaValue m -> IO (GammaValue m)) -> GammaModifierT m a -> m a
runGammaModifierT :: (GammaValue m -> IO (GammaValue m)) -> GammaModifierT m a -> m a
runGammaModifierT GammaValue m -> IO (GammaValue m)
modify GammaModifierT m a
tma = ReaderT (GammaValue m -> IO (GammaValue m)) m a
-> (GammaValue m -> IO (GammaValue m)) -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (GammaModifierT m a
-> ReaderT (GammaValue m -> IO (GammaValue m)) m a
forall (m :: * -> *) a.
GammaModifierT m a
-> ReaderT (GammaValue m -> IO (GammaValue m)) m a
unGammaModifierT GammaModifierT m a
tma) GammaValue m -> IO (GammaValue m)
modify