packages feed

blucontrol-0.7.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.ApplyValue
import Blucontrol.Monad.Control
import Blucontrol.Monad.PrepareValue

-- | Run the loop, using `prepareValue`, `applyValue` and `doInbetween`.
loopRecolor :: (ControlConstraint mc (StM mp (StM ma ())), MonadBaseControl IO mc, MonadBaseControl IO mp, MonadBaseControl IO ma, MonadApplyValue ma, MonadControl mc, MonadPrepareValue mp)
            => RunInBase mc IO
            -> RunInBase mp IO
            -> RunInBase ma IO
            -> (PreparedValue mp -> ApplicableValue ma)
            -> IO ()
loopRecolor runC runP runA coerceValue = do

      -- Use `preparedValue` and give the result to `applyValue`.
      -- Then use the result of `applyValue` and give it to `doInbetween` including the monadic state.
      -- The argument is an initial monadic state.
  let doRecolor x =
        runC $ do
          x1 <- restoreM x
          x4 <- liftBase $ do
            runP $ do
              x2 <- restoreM x1
              value <- coerceValue <$> preparedValue
              liftBase $ runA $ do
                x3 <- restoreM x2
                applyValue value
                pure x3
          let currentRecolorValue =
                runP $ do
                  -- TODO: `unsafeCoerce` is necessary because of GHC limitations with type families.
                  -- `unsafeCoerce` will act like `id`.
                  x5 <- restoreM $ unsafeCoerce x4
                  liftBase $ runA $ 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 (doRecolor x)

  -- Initialize the monadic state.
  initStM <- runC $ liftBase $ runP $ liftBase $ runA $ 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