Transcript

Toward Monad Transformers

Antoine Leblanc - @nicuveoFunctional Programmers Paris

2015-04-01

Outline

▶ Monads!

▶ Our mission

▶ Transformers

▶ Building RestT

▶ Wrapping up

1 / 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

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

3 / 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

Monad laws

Using (>=>)

return >=> f ≡ f

f >=> return ≡ f

(f >=> g) >=> h ≡ f >=> (g >=> h)

4 / 34

Do notation

do { a ← f ; m } ≡ f >>= λa → m

do { f ; m } ≡ f >> m

do { m } ≡ m

5 / 34

Do sugar

f >>= λa →g >>= λb →

h >>= λc →return (a, b, c)

doa ← fb ← gc ← hreturn (a, b, c)

6 / 34

Do sugar

f >>= λa →g >>= λb →

h >>= λc →return (a, b, c)

doa ← fb ← gc ← hreturn (a, b, c)

6 / 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

Outline

▶ Monads

▶ Our mission!

▶ Transformers

▶ Building RestT

▶ Wrapping up

14 / 34

REST client

▶ Authenticate▶ Issue simple commands▶ That’s it!

15 / 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 :: String → IO ByteString

17 / 34

Problem

import Network.HTTP.ConduitsimpleHttp :: String → IO ByteString

IO!

17 / 34

Problem

import Network.HTTP.ConduitsimpleHttp :: String → IO ByteString

wait…

17 / 34

Problem

import Network.HTTP.ConduitsimpleHttp :: MonadIO m ⇒

String → m ByteString

…MonadIO?

17 / 34

State in IO

▶ MVar?▶ IORef?

...add State and Either monads to IO?

18 / 34

State in IO

▶ MVar?▶ IORef?

...add State and Either monads to IO?

18 / 34

Outline

▶ Monads

▶ Our mission

▶ Transformers!

▶ Building RestT

▶ Wrapping up

19 / 34

All the way down

▶ Monad generalization▶ Extra monad parameter▶ Monad stacks

20 / 34

Monad→ MonadT

data State s a = { ... }get :: State s sput :: s → State s ()

Mister

21 / 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

Outline

▶ Monads

▶ Our mission

▶ Transformers

▶ Building RestT!

▶ Wrapping up

25 / 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

Outline

▶ Monads

▶ Our mission

▶ Transformers

▶ Building RestT

▶ Wrapping up!

32 / 34

What have we learned today?

▶ Transformers: stack monads.▶ Combine their powers!▶ Hide stack details.

33 / 34

This is the end. You are free.

Thank you.Any questions?

34 / 34


Top Related