Post on 16-Jul-2015

244 views

Category:

## Software

Embed Size (px)

TRANSCRIPT

• Toward Monad TransformersAntoine Leblanc - @nicuveo

Functional Programmers Paris

2015-04-01

• Outline

I Monads!I Our missionI TransformersI Building RestTI Wrapping up

1 / 34

• Introduction

What I Wish I Knew When Learning Haskell

2 / 34

• Introduction

What I Wish I Knew When Learning Haskell

2 / 34

• Introduction

What I Wish I Knew When Learning Haskell

2 / 34

• Introduction

What I Wish I Knew When Learning Haskell

2 / 34

• Introduction

What I Wish I Knew When Learning Haskell

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

• 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

Using (>>=)

return a >>= f f am >>= return m(m >>= f) >>= g m >>= (x f x >>= g)

4 / 34

Using (>=>)

return >=> f ff >=> return f(f >=> g) >=> h f >=> (g >=> h)

4 / 34

• Do notation

do { a f ; m } f >>= a mdo { 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 f

b gc hreturn (a, b, c)

6 / 34

Maybe getUser :: Id Maybe User

Either a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO StringReader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)

7 / 34

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error Value

List allNextTurns :: Board [Board]IO httpGet :: Url IO StringReader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)

7 / 34

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]

IO httpGet :: Url IO StringReader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)

7 / 34

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO String

Reader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)

7 / 34

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO StringReader 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

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO StringReader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)

State s runState :: Reader s a s (a, s)

7 / 34

Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO StringReader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)

7 / 34

(>>=) :: ( )

runReader :: ( )8 / 34

data Conf = { color :: Color, size :: Int }

formatter :: String Reader Conf Stringformatter p = do

format :: Conf String Stringformat c s = runReader (textFormatter s) c

9 / 34

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 y

Writer (a + b, "Plus")11 / 34

• State MonadState Green :: State Yellow ::

(>>=) :: ( )

runState :: ( ) 12 / 34

• State Example

data GameInfo = GameInfo {turn :: Int,score :: Int}

skipTurn :: State GameInfo ()skipTurn = do

t gets turns gets score

put \$ GameInfo (t + 1) (s `div` 2)

13 / 34

• Outline

I MonadsI Our mission!I TransformersI Building RestTI Wrapping up

14 / 34

• REST client

I AuthenticateI Issue simple commandsI Thats it!

15 / 34

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

String m ByteString

17 / 34

• State in IO

I MVar?I IORef?

18 / 34

• State in IO

I MVar?I IORef?

18 / 34

• Outline

I MonadsI Our missionI Transformers!I Building RestTI Wrapping up

19 / 34

• All the way down

20 / 34

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

Mister21 / 34

data StateT s m a = { ... }get :: MonadState s m m sput :: MonadState s m s m ()

MisterT21 / 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) whereget = lift getput = lift . put

23 / 34

• n 2

24 / 34

• Outline

I MonadsI Our missionI TransformersI Building RestT!I Wrapping up

25 / 34

• Handling errors: ErrorTtype ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)

type RestT m = ErrorT ErrorMsg m

..

m

.ErrorT ErrorMsg a

26 / 34

• Handling errors: ErrorTtype 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: ErrorTtype 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: StateTtype 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: StateTtype 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: StateTtype 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: ReaderTtype ErrorMsg = Stringtype

Recommended