module Problem1a where
class Monad m => GameMonad m where
extraLife :: m ()
getLives :: m Int
checkPoint :: m a -> m a
die :: m a
newtype Game a = Game { unGame :: Int -> Result a }
type Result a = Either Int (a, Int)
-- Alternative definitions:
-- type Result a = (Maybe a, Int)
-- data Result a = GameOver | Died Int | Survived a Int
instance Monad Game where
return x = Game $ \n -> Right (x, n)
m >>= f = Game $ \n -> case unGame m n of
Left n -> Left n
Right (x, n) -> unGame (f x) n
instance GameMonad Game where
extraLife = Game $ \n -> Right ((), n + 1)
getLives = Game $ \n -> Right (n, n)
die = Game $ \n -> Left (n - 1)
checkPoint m = Game $ \n -> case unGame m n of
Left n | n > 0 -> unGame (checkPoint m) n
| otherwise -> Left 0
Right (x, n) -> Right (x, n)
runGame :: Game a -> Int -> Maybe (a, Int)
runGame m n = case unGame m n of
Left _ -> Nothing
Right r -> Just r