packages feed

blucontrol-0.6.0.0: src/Blucontrol/Main/Control.hs

module Blucontrol.Main.Control (
  loopRecolor
) where

import Control.Monad
import Control.Monad.Base
import Control.Monad.Trans.Control
import Unsafe.Coerce

import Blucontrol.Monad.Control
import Blucontrol.Monad.Gamma
import Blucontrol.Monad.Recolor

-- | Run the loop, using `gamma`, `recolor` and `doInbetween`.
loopRecolor :: (MonadBaseControl IO m, MonadBaseControl IO g, MonadBaseControl IO r, MonadControl m, MonadGamma g, MonadRecolor r, ControlConstraint m (StM g (StM r ())))
            => RunInBase m IO
            -> RunInBase g IO
            -> RunInBase r IO
            -> (GammaValue g -> RecolorValue r)
            -> IO ()
loopRecolor runC runG runR coerceValue = do

      -- Use `gamma` and give the result to `recolor`.
      -- Then use the result of `recolor` and give it to `doInbetween` including the monadic state.
      -- The argument is an initial monadic state.
  let doRecolorGamma x =
        runC $ do
          x1 <- restoreM x
          x4 <- liftBase $ do
            runG $ do
              x2 <- restoreM x1
              value <- coerceValue <$> gamma
              liftBase $ runR $ do
                x3 <- restoreM x2
                recolor value
                pure x3
          let currentRecolorValue =
                runG $ do
                  -- TODO: `unsafeCoerce` is necessary because of GHC limitations with type families.
                  -- `unsafeCoerce` will act like `id`.
                  x5 <- restoreM $ unsafeCoerce x4
                  liftBase $ runR $ void $ restoreM x5
          currentRecolorValue' <- liftBase currentRecolorValue
          doInbetween currentRecolorValue'
          pure x4

      -- Run `doLoopRecolor` in a recursive loop while passing the monadic state explicitly.
      doLoopRecolor x = doLoopRecolor =<< liftBase (doRecolorGamma x)

  -- Initialize the monadic state.
  initStM <- runC $ liftBase $ runG $ liftBase $ runR $ pure undefined

  -- Start an infinite loop.
  -- TODO: `unsafeCoerce` is necessary because of GHC limitations with type families.
  -- `unsafeCoerce` will act like `id`.
  doLoopRecolor $ unsafeCoerce initStM