{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
-- Copyright : (c) 2017 Harendra Kumar
-- (c) 2013, 2014 Gabriel Gonzalez
--
-- This example is adapted from Gabriel Gonzalez's pipes-concurrency package.
-- https://hackage.haskell.org/package/pipes-concurrency-2.0.8/docs/Pipes-Concurrent-Tutorial.html
#if !(MIN_VERSION_base(4,11,0))
import Data.Semigroup ((<>))
#endif
import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.State (MonadState, get, modify, runStateT)
import Data.Function ((&))
import Streamly.Prelude (MonadAsync, SerialT)
import qualified Streamly.Prelude as Stream
data Event = Quit | Harm Int | Heal Int deriving (Show)
userAction :: MonadAsync m => SerialT m Event
userAction = Stream.repeatM $ liftIO askUser
where
askUser = do
command <- getLine
case command of
"potion" -> return (Heal 10)
"harm" -> return (Harm 10)
"quit" -> return Quit
_ -> putStrLn "Type potion or harm or quit" >> askUser
acidRain :: MonadAsync m => SerialT m Event
acidRain =
Stream.repeatM (liftIO $ return $ Harm 1) -- AsyncT m Event
& Stream.constRate 1 -- AsyncT m Event
& Stream.fromAsync -- SerialT m Event
data Result = Check | Done
runEvents :: (MonadAsync m, MonadState Int m) => SerialT m Result
runEvents = do
event <- userAction `Stream.parallel` acidRain -- SerialT m Event
case event of
Harm n -> modify (\h -> h - n) >> return Check
Heal n -> modify (\h -> h + n) >> return Check
Quit -> return Done
data Status = Alive | GameOver deriving Eq
getStatus :: (MonadAsync m, MonadState Int m) => Result -> m Status
getStatus result =
case result of
Done -> liftIO $ putStrLn "You quit!" >> return GameOver
Check -> do
h <- get
liftIO $ if (h <= 0)
then putStrLn "You die!" >> return GameOver
else putStrLn ("Health = " <> show h) >> return Alive
main :: IO ()
main = do
putStrLn "Your health is deteriorating due to acid rain,\\
\ type \"potion\" or \"quit\""
let runGame =
Stream.mapM getStatus runEvents -- SerialT (StateT Int IO) Status
& Stream.drainWhile (== Alive) -- StateT Int IO ()
void $ runStateT runGame 60