-
Notifications
You must be signed in to change notification settings - Fork 3
/
AcidRain.hs
72 lines (58 loc) · 2.41 KB
/
AcidRain.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{-# 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
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.State (MonadState, get, modify)
import Data.Function ((&))
import Streamly.Data.Stream.Prelude (MonadAsync, Stream)
import qualified Streamly.Data.Fold as Fold
import qualified Streamly.Data.Stream.Prelude as Stream
data Event = Quit | Harm Int | Heal Int deriving (Eq, Show)
userAction :: MonadAsync m => Stream 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 => Stream m Event
acidRain = Stream.parRepeatM (Stream.constRate 1) (return $ Harm 1)
parallel :: MonadAsync m => [Stream m a] -> Stream m a
parallel = Stream.parList (Stream.eager True)
data Result = Check | Done
runEvents :: (MonadAsync m, MonadState Int m) => Stream m Result
runEvents =
Stream.mapM f $ parallel [userAction, acidRain]
where
f 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\""
Stream.mapM getStatus runEvents -- Stream (StateT Int IO) Status
& Stream.runStateT (pure 60) -- Stream IO (Int, Status)
& fmap snd -- Stream IO Status
& Stream.fold (Fold.takeEndBy (/= Alive) Fold.drain) -- IO ()
return ()