toward haskell transformers
TRANSCRIPT
Introduction
What I Wish I Knew When Learning Haskell
1. Don’t read the monad tutorials.2. No really, don’t read the monad tutorials.
…8. Don’t write monad-analogy tutorials.
2 / 34
Introduction
What I Wish I Knew When Learning Haskell
1. Don’t read the monad tutorials.
2. No really, don’t read the monad tutorials.…
8. Don’t write monad-analogy tutorials.
2 / 34
Introduction
What I Wish I Knew When Learning Haskell
1. Don’t read the monad tutorials.2. No really, don’t read the monad tutorials.
…8. Don’t write monad-analogy tutorials.
2 / 34
Introduction
What I Wish I Knew When Learning Haskell
1. Don’t read the monad tutorials.2. No really, don’t read the monad tutorials.
…
8. Don’t write monad-analogy tutorials.
2 / 34
Introduction
What I Wish I Knew When Learning Haskell
1. Don’t read the monad tutorials.2. No really, don’t read the monad tutorials.
…8. Don’t write monad-analogy tutorials.
2 / 34
Typeclass
class Monad m wherereturn :: a → m a(>>=) :: m a → (a → m b) → m b
adit.io3 / 34
Typeclass
class Monad m wherereturn :: a → m a(>>=) :: m a → (a → m b) → m b
(>>) :: Monad m ⇒ m a → m b → m b(>=>) :: Monad m ⇒ (a → m b)
→ (b → m c)→ (a → m c)
3 / 34
Monad laws
Using (>>=)
return a >>= f ≡ f a
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (λx → f x >>= g)
4 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
ALL TEH MONADS
Maybe getUser :: Id → Maybe User
Either a parse :: String → Either Error Value
List allNextTurns :: Board → [Board]
IO httpGet :: Url → IO String
Reader r runReader :: Reader r a → r → a
Writer w runWriter :: Writer w a → (a, w)
State s runState :: Reader s a → s → (a, s)
7 / 34
Reader Monad
Reader Green :: ■→ ■Reader Yellow :: ■→ ■
(>>=) :: ■→ ■→ (■→ ■→ ■ )→ ■→ ■
runReader :: ■→ ■ → (■→ ■)8 / 34
Reader example
data Conf = { color :: Color, size :: Int }
formatter :: String → Reader Conf Stringformatter p = do
c ← asks colors ← asks sizereturn (undefined) -- TODO
format :: Conf → String → Stringformat c s = runReader (textFormatter s) c
9 / 34
Writer Monad
Writer Green :: ■ ■Writer Yellow :: ■ ■
(>>=) :: ■ ■→ (■→ ■ ■ )→ ■ ■
runWriter :: ■ ■ → (■ ■)10 / 34
Writer example
type Log = [String]type Debug = Writer Log
value :: Int → Debug Intvalue x = Writer (x, ["Value"])
plus :: Debug Int → Debug Int → Debug Intplus x y = do
a ← xb ← yWriter (a + b, "Plus")
11 / 34
State Monad
State Green :: ■→ ■ ■State Yellow :: ■→ ■ ■
(>>=) :: ■→ ■ ■→ (■→ ■→ ■ ■ )→ ■→ ■ ■
runState :: ■→ ■ ■→ (■→ ■ ■)
12 / 34
State Example
data GameInfo = GameInfo {turn :: Int,score :: Int
}
skipTurn :: State GameInfo ()skipTurn = do
t ← gets turns ← gets scoreput $ GameInfo (t + 1) (s `div` 2)
13 / 34
Monadic syntax?
main = run $ dosetServerUrl "http://server.com/api"setCredentials "guest" "guest"authenticateresult ← request "server.listMyStuff"print $ format result
16 / 34
Problem
import Network.HTTP.ConduitsimpleHttp :: MonadIO m ⇒
String → m ByteString
…MonadIO?
17 / 34
Monad→ MonadT
data StateT s m a = { ... }get :: MonadState s m ⇒ m sput :: MonadState s m ⇒ s → m ()
MisterT
21 / 34
Lifting
example :: CustomT IO Intexample = do
customStuff 1lift $ putStrLn "Turtles!"customStuff 2
22 / 34
Lifting
example :: CustomT (MaybeT IO) Intexample = do
customStuff 1lift $ lift $ putStrLn "Turtles!"customStuff 2
22 / 34
Instances
class Monad m ⇒ MonadState s m whereget :: m sput :: s → m ()
instance MonadState s m ⇒MonadState s (ReaderT r m) where
get = lift getput = lift . put
23 / 34
n 2
IO ↔ MonadIO ↔ liftIO
StateT ↔ MonadState ↔ get
ReaderT ↔ MonadReader ↔ ask
WriterT ↔ MonadWriter ↔ tell
ErrorT ↔ MonadError ↔ throwError
24 / 34
Handling errors: ErrorT
type ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ErrorT ErrorMsg m
..
m
.
ErrorT ErrorMsg a
26 / 34
Handling errors: ErrorT
type ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ErrorT ErrorMsg m
run :: RestT m a → Result m arun = runErrorT
..
m
.
ErrorT ErrorMsg a
26 / 34
Handling errors: ErrorT
type ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ErrorT ErrorMsg m
run :: RestT m a → Result m arun = runErrorT
liftRest :: m a → RestT m aliftRest = lift
..
m
.
ErrorT ErrorMsg a
26 / 34
Adding session: StateT
type ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = StateT Token (ErrorT ErrorMsg m)
..
m
.
ErrorT ErrorMsg
.StateT Token a
27 / 34
Adding session: StateT
type ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = StateT Token (ErrorT ErrorMsg m)
run :: Token → RestT m a → Result m arun t x = runErrorT $ evalStateT x t
..
m
.
ErrorT ErrorMsg
.StateT Token a
27 / 34
Adding session: StateT
type ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = StateT Token (ErrorT ErrorMsg m)
run :: Token → RestT m a → Result m arun t x = runErrorT $ evalStateT x t
liftRest :: m a → RestT m aliftRest = lift . lift
..
m
.
ErrorT ErrorMsg
.StateT Token a
27 / 34
Dependency injection: ReaderT
type ErrorMsg = Stringtype Token = Stringtype Getter m = String → m Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))
..
m
.
ErrorT ErrorMsg
.StateT Token
.ReaderT (Getter m) a
28 / 34
Dependency injection: ReaderT
type ErrorMsg = Stringtype Token = Stringtype Getter m = String → m Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))
run :: Getter m → Token → RestT m a → Result m arun g t x = runErrorT $ evalStateT (runReaderT x g) t
..
m
.
ErrorT ErrorMsg
.StateT Token
.ReaderT (Getter m) a
28 / 34
Dependency injection: ReaderT
type ErrorMsg = Stringtype Token = Stringtype Getter m = String → m Stringtype Result m a = m (Either ErrorMsg a)
type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))
run :: Getter m → Token → RestT m a → Result m arun g t x = runErrorT $ evalStateT (runReaderT x g) t
liftRest :: m a → RestT m aliftRest = lift . lift . lift
..
m
.
ErrorT ErrorMsg
.StateT Token
.ReaderT (Getter m) a
28 / 34
YAY!
request :: String → RestT m Stringrequest method = do
getter ← asktoken ← getlet q = query method tokenliftRest $ getter q
29 / 34
AT LAST!
authenticate :: RestT m ()authenticate = do
token ← getunless (null token)(throwError "already logged in")
answer ← request "getToken"token ← parse answerput token
30 / 34
WOOOO!
main = void $ run httpGet emptyToken $ doauthenticateanswer ← request "showMyStuff"liftIO $ print answer
31 / 34
What have we learned today?
▶ Transformers: stack monads.▶ Combine their powers!▶ Hide stack details.
33 / 34