import Control.Applicative import Control.Monad -- Reader monad definition newtype Reader r a = Reader { runReader :: r -> a } -- Functor instance for Reader instance Functor (Reader r) where fmap f (Reader ra) = Reader $ \r -> f (ra r) -- Applicative instance for Reader instance Applicative (Reader r) where pure x = Reader $ \_ -> x (Reader rf) <*> (Reader ra) = Reader $ \r -> rf r (ra r) -- Monad instance for Reader instance Monad (Reader r) where return = pure (Reader ra) >>= f = Reader $ \r -> runReader (f (ra r)) r -- Get the whole environment ask :: Reader r r ask = Reader id -- Get a specific part of the environment asks :: (r -> a) -> Reader r a asks f = Reader f -- Environment data type data Env = Env { userName :: String, userId :: Int, userLevel :: Int } getUserInfo :: Reader Env String getUserInfo = do name <- asks userName uid <- asks userId level <- asks userLevel return $ "User: " ++ name ++ ", ID: " ++ show uid ++ ", Level: " ++ show level isValidUser :: Reader Env Bool isValidUser = do uid <- asks userId return $ uid > 0 isVIP :: Reader Env Bool isVIP = do valid <- isValidUser level <- asks userLevel return $ valid && level == 2 -- Main function to run the computations main :: IO () main = do let env1 = Env { userName = "Alice", userId = 42, userLevel = 1 } let env2 = Env { userName = "Bob", userId = -1, userLevel = 2 } let env3 = Env { userName = "City", userId = 29, userLevel = 2 } let envs = [env1, env2, env3] let info = runReader getUserInfo env1 let valid = runReader isValidUser env1 let vip = runReader isVIP env1 putStrLn info putStrLn $ "Is valid user: " ++ show valid putStrLn $ "Is VIP user: " ++ show vip