typesafe-precure-0.11.0.1: src/ACME/PreCure/Monad.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module ACME.PreCure.Monad
( PreCureMonad
, EpisodeConfig(lineIntervalMicroSec)
, defaultEpisodeConfig
, speak
, say
, runPreCureMonad
, execPreCureMonad
, composeEpisode
, printEpisode
, printEpisodeWith
, hPrintEpisode
, hPrintEpisodeWith
, transform
, purify
, purifyWithoutItem
) where
import qualified Control.Arrow as Arrow
import qualified Control.Concurrent as Concurrent
import qualified Control.Monad as Monad
import Control.Monad.Trans.Writer.CPS (Writer, execWriter, runWriter, tell)
import qualified Data.DList as DList
import qualified System.IO as IO
import ACME.PreCure.Types
newtype PreCureMonad a =
PreCureMonad { runPreCureMonadD :: Writer (DList.DList String) a }
deriving (Functor, Applicative, Monad)
newtype EpisodeConfig =
EpisodeConfig
{ lineIntervalMicroSec :: Int }
defaultEpisodeConfig :: EpisodeConfig
defaultEpisodeConfig =
EpisodeConfig $ 1 * 1000 * 1000
speak :: [String] -> PreCureMonad ()
speak =
PreCureMonad . tell . DList.fromList
say :: String -> PreCureMonad ()
say =
PreCureMonad . tell . DList.singleton
composeEpisode :: PreCureMonad a -> [String]
composeEpisode =
execPreCureMonad
runPreCureMonad :: PreCureMonad a -> (a, [String])
runPreCureMonad =
Arrow.second DList.toList . runWriter . runPreCureMonadD
execPreCureMonad :: PreCureMonad a -> [String]
execPreCureMonad =
DList.toList . execWriter . runPreCureMonadD
printEpisode :: PreCureMonad a -> IO ()
printEpisode =
printEpisodeWith defaultEpisodeConfig
hPrintEpisode :: IO.Handle -> PreCureMonad a -> IO ()
hPrintEpisode =
(`hPrintEpisodeWith` defaultEpisodeConfig)
printEpisodeWith :: EpisodeConfig -> PreCureMonad a -> IO ()
printEpisodeWith =
hPrintEpisodeWith IO.stdout
hPrintEpisodeWith :: IO.Handle -> EpisodeConfig -> PreCureMonad a -> IO ()
hPrintEpisodeWith h cfg a = do
let interval = lineIntervalMicroSec cfg
Monad.forM_ (composeEpisode a) $ \s -> do
IO.hPutStrLn h s
IO.hFlush h
Concurrent.threadDelay interval
transform :: (Transformation g' i') => g' -> i' -> PreCureMonad (Style g' i')
transform g i = do
speak $ transformationSpeech g i
return $ transformedStyle g i
purify
:: (Purification p' i')
=> p' -> i' -> PreCureMonad ()
purify p =
speak . purificationSpeech p
purifyWithoutItem
:: (NonItemPurification p')
=> p' -> PreCureMonad ()
purifyWithoutItem =
speak . nonItemPurificationSpeech