main :: IO ()
main = do
putStrLn "Hello, what is your name?"
name <- readLine
putStrLn ("Hello " <> name <> "!")
IO
, State
, Reader
, Writer
, Except
, []
, Maybe
, …
You are free to create your own as long as you obey monad laws.
Monads do not compose well
State s a
→ Monad m => StateT s m a
newtype ProtocolT m a = ProtocolT (ReaderT Request (WriterT Response (MaybeT m)) a)
deriving (Applicative, Functor, Monad)
:-(
type Protocol = '[Reader Request, Writer Response, Exc ()]
action :: Members Protocol effs => Eff effs a
-- action :: Monad m => ProtocolT m a
Approach to computational effects based on a premise that impure behaviour arises from a set of operations
Eff
)action
uses only those effects it requires, but stack can contain any, even our custom ones.data Console s where
PutStrLn :: String -> Console ()
GetLine :: Console String
putStrLn' :: Member Console r => String -> Eff r ()
putStrLn' = send . PutStrLn
getLine' :: Member Console r => Eff r String
getLine' = send GetLine
hello :: Member Console effs => Eff effs ()
hello = do
putStrLn' "Hello, what is your name?"
name <- readLine'
putStrLn' ("Hello " <> name <> "!")
runConsoleIO :: Member IO r => Eff (Console ': r) w -> Eff r w
main :: IO ()
main = runM (runConsoleIO hello)
-- | | |
-- IO () -' | |
-- Eff '[IO] () -' |
-- Eff '[Console, IO] () -'
runConsolePure :: [String] -> Eff (Console ': r) a
-> Eff r (a, ([String], [String]))
-- ^ (value, (unconsumed input, produced output))
:-)
lift
, …)exampleEcho :: Member Console r => Eff r ()
exampleEcho = forever $ do
putStrLn' "Send me something to echo..."
s <- getLine'
putStrLn' ("Thanks for sending " ++ show s)
mainEcho :: IO ()
mainEcho = runM (runConsoleM exampleEcho)
-- | | |
-- IO () -' | |
-- Eff '[IO] () -' |
-- Eff '[Console, IO] () -'
data Capitalize v where
Capitalize :: String -> Capitalize String
capitalize :: Member Capitalize r => String -> Eff r String
capitalize = send . Capitalize
runCapitalizeM :: Eff (Capitalize ': r) w -> Eff r w
exampleCapitalize :: Members '[Console, Capitalize] effs => Eff effs ()
exampleCapitalize = forever $ do
putStrLn' "Send me something to capitalize..."
l <- getLine'
when (null l) exitSuccess'
capitalize l >>= putStrLn'
mainCapitalize1 :: IO ()
mainCapitalize1 = runM (runConsoleM (runCapitalizeM exampleCapitalize))
-- | | | |
-- IO () -' | | |
-- Eff '[IO] () -' | |
-- Eff '[Console, IO] () -' |
-- Eff '[Capitalize, Console, IO] () -'
mainCapitalize2 :: IO ()
mainCapitalize2 = runM (runCapitalizeM (runConsoleM exampleCapitalize))
-- | | | |
-- IO () -' | | |
-- Eff '[IO] () -' | |
-- Eff '[Capitalize, IO] () -' |
-- Eff '[Console, Capitalize, IO] () -'
Functor
, Applicative
, Monad
Reader
Writer
State
Exception
NonDet
Coroutine
Fresh
Trace
Cut