Toward Haskell Transformers

Download Toward Haskell Transformers

Post on 16-Jul-2015

244 views

Category:

Software

0 download

Embed Size (px)

TRANSCRIPT

<ul><li><p>Toward Monad TransformersAntoine Leblanc - @nicuveo</p><p>Functional Programmers Paris</p><p>2015-04-01</p></li><li><p>Outline</p><p>I Monads!I Our missionI TransformersI Building RestTI Wrapping up</p><p>1 / 34</p></li><li><p>Introduction</p><p>What I Wish I Knew When Learning Haskell</p><p>1. Dont read the monad tutorials.2. No really, dont read the monad tutorials.</p><p>8. Dont write monad-analogy tutorials.</p><p>2 / 34</p></li><li><p>Introduction</p><p>What I Wish I Knew When Learning Haskell</p><p>1. Dont read the monad tutorials.</p><p>2. No really, dont read the monad tutorials.</p><p>8. Dont write monad-analogy tutorials.</p><p>2 / 34</p></li><li><p>Introduction</p><p>What I Wish I Knew When Learning Haskell</p><p>1. Dont read the monad tutorials.2. No really, dont read the monad tutorials.</p><p>8. Dont write monad-analogy tutorials.</p><p>2 / 34</p></li><li><p>Introduction</p><p>What I Wish I Knew When Learning Haskell</p><p>1. Dont read the monad tutorials.2. No really, dont read the monad tutorials.</p><p>8. Dont write monad-analogy tutorials.</p><p>2 / 34</p></li><li><p>Introduction</p><p>What I Wish I Knew When Learning Haskell</p><p>1. Dont read the monad tutorials.2. No really, dont read the monad tutorials.</p><p>8. Dont write monad-analogy tutorials.</p><p>2 / 34</p></li><li><p>Typeclass</p><p>class Monad m wherereturn :: a m a</p><p>(&gt;&gt;=) :: m a (a m b) m b</p><p>3 / 34</p></li><li><p>Typeclass</p><p>class Monad m wherereturn :: a m a</p><p>(&gt;&gt;=) :: m a (a m b) m b</p><p>adit.io3 / 34</p></li><li><p>Typeclass</p><p>class Monad m wherereturn :: a m a</p><p>(&gt;&gt;=) :: m a (a m b) m b</p><p>(&gt;&gt;) :: Monad m m a m b m b(&gt;=&gt;) :: Monad m (a m b)</p><p> (b m c) (a m c)</p><p>3 / 34</p></li><li><p>Monad laws</p><p>Using (&gt;&gt;=)</p><p>return a &gt;&gt;= f f am &gt;&gt;= return m(m &gt;&gt;= f) &gt;&gt;= g m &gt;&gt;= (x f x &gt;&gt;= g)</p><p>4 / 34</p></li><li><p>Monad laws</p><p>Using (&gt;=&gt;)</p><p>return &gt;=&gt; f ff &gt;=&gt; return f(f &gt;=&gt; g) &gt;=&gt; h f &gt;=&gt; (g &gt;=&gt; h)</p><p>4 / 34</p></li><li><p>Do notation</p><p>do { a f ; m } f &gt;&gt;= a mdo { f ; m } f &gt;&gt; m</p><p>do { m } m</p><p>5 / 34</p></li><li><p>Do sugar</p><p>f &gt;&gt;= a g &gt;&gt;= b </p><p>h &gt;&gt;= c return (a, b, c)</p><p>doa fb gc hreturn (a, b, c)</p><p>6 / 34</p></li><li><p>Do sugar</p><p>f &gt;&gt;= a g &gt;&gt;= b </p><p>h &gt;&gt;= c return (a, b, c)</p><p>doa f</p><p>b gc hreturn (a, b, c)</p><p>6 / 34</p></li><li><p>ALL TEH MONADS</p><p>Maybe getUser :: Id Maybe User</p><p>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)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>Maybe getUser :: Id Maybe UserEither a parse :: String Either Error Value</p><p>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)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]</p><p>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)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>Maybe getUser :: Id Maybe UserEither a parse :: String Either Error ValueList allNextTurns :: Board [Board]IO httpGet :: Url IO String</p><p>Reader r runReader :: Reader r a r aWriter w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>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</p><p>Writer w runWriter :: Writer w a (a, w)State s runState :: Reader s a s (a, s)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>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)</p><p>State s runState :: Reader s a s (a, s)</p><p>7 / 34</p></li><li><p>ALL TEH MONADS</p><p>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)</p><p>7 / 34</p></li><li><p>Reader Monad</p><p>Reader Green :: Reader Yellow :: </p><p>(&gt;&gt;=) :: ( ) </p><p>runReader :: ( )8 / 34</p></li><li><p>Reader example</p><p>data Conf = { color :: Color, size :: Int }</p><p>formatter :: String Reader Conf Stringformatter p = do</p><p>c asks colors asks sizereturn (undefined) -- TODO</p><p>format :: Conf String Stringformat c s = runReader (textFormatter s) c</p><p>9 / 34</p></li><li><p>Writer Monad</p><p>Writer Green :: Writer Yellow :: </p><p>(&gt;&gt;=) :: ( ) </p><p>runWriter :: ( )10 / 34</p></li><li><p>Writer example</p><p>type Log = [String]type Debug = Writer Log</p><p>value :: Int Debug Intvalue x = Writer (x, ["Value"])</p><p>plus :: Debug Int Debug Int Debug Intplus x y = do</p><p>a xb y</p><p>Writer (a + b, "Plus")11 / 34</p></li><li><p>State MonadState Green :: State Yellow :: </p><p>(&gt;&gt;=) :: ( ) </p><p>runState :: ( ) 12 / 34</p></li><li><p>State Example</p><p>data GameInfo = GameInfo {turn :: Int,score :: Int}</p><p>skipTurn :: State GameInfo ()skipTurn = do</p><p>t gets turns gets score</p><p>put $ GameInfo (t + 1) (s `div` 2)</p><p>13 / 34</p></li><li><p>Outline</p><p>I MonadsI Our mission!I TransformersI Building RestTI Wrapping up</p><p>14 / 34</p></li><li><p>REST client</p><p>I AuthenticateI Issue simple commandsI Thats it!</p><p>15 / 34</p></li><li><p>Monadic syntax?</p><p>main = run $ dosetServerUrl "http://server.com/api"setCredentials "guest" "guest"authenticateresult request "server.listMyStuff"print $ format result</p><p>16 / 34</p></li><li><p>Problem</p><p>import Network.HTTP.ConduitsimpleHttp :: String IO ByteString</p><p>17 / 34</p></li><li><p>Problem</p><p>import Network.HTTP.ConduitsimpleHttp :: String IO ByteString</p><p>IO!</p><p>17 / 34</p></li><li><p>Problem</p><p>import Network.HTTP.ConduitsimpleHttp :: String IO ByteString</p><p>wait</p><p>17 / 34</p></li><li><p>Problem</p><p>import Network.HTTP.ConduitsimpleHttp :: MonadIO m </p><p>String m ByteString</p><p>MonadIO?</p><p>17 / 34</p></li><li><p>State in IO</p><p>I MVar?I IORef?</p><p>...add State and Either monads to IO?</p><p>18 / 34</p></li><li><p>State in IO</p><p>I MVar?I IORef?</p><p>...add State and Either monads to IO?</p><p>18 / 34</p></li><li><p>Outline</p><p>I MonadsI Our missionI Transformers!I Building RestTI Wrapping up</p><p>19 / 34</p></li><li><p>All the way down</p><p>I Monad generalizationI Extra monad parameterI Monad stacks</p><p>20 / 34</p></li><li><p>Monad MonadT</p><p>data State s a = { ... }get :: State s sput :: s State s ()</p><p>Mister21 / 34</p></li><li><p>Monad MonadT</p><p>data StateT s m a = { ... }get :: MonadState s m m sput :: MonadState s m s m ()</p><p>MisterT21 / 34</p></li><li><p>Lifting</p><p>example :: CustomT IO Intexample = do</p><p>customStuff 1lift $ putStrLn "Turtles!"customStuff 2</p><p>22 / 34</p></li><li><p>Lifting</p><p>example :: CustomT (MaybeT IO) Intexample = do</p><p>customStuff 1lift $ lift $ putStrLn "Turtles!"customStuff 2</p><p>22 / 34</p></li><li><p>Instances</p><p>class Monad m MonadState s m whereget :: m sput :: s m ()</p><p>instance MonadState s m MonadState s (ReaderT r m) whereget = lift getput = lift . put</p><p>23 / 34</p></li><li><p>n 2</p><p>IO MonadIO liftIOStateT MonadState getReaderT MonadReader askWriterT MonadWriter tellErrorT MonadError throwError</p><p>24 / 34</p></li><li><p>Outline</p><p>I MonadsI Our missionI TransformersI Building RestT!I Wrapping up</p><p>25 / 34</p></li><li><p>Handling errors: ErrorTtype ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ErrorT ErrorMsg m</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg a</p><p>26 / 34</p></li><li><p>Handling errors: ErrorTtype ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ErrorT ErrorMsg m</p><p>run :: RestT m a Result m arun = runErrorT</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg a</p><p>26 / 34</p></li><li><p>Handling errors: ErrorTtype ErrorMsg = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ErrorT ErrorMsg m</p><p>run :: RestT m a Result m arun = runErrorT</p><p>liftRest :: m a RestT m aliftRest = lift</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg a</p><p>26 / 34</p></li><li><p>Adding session: StateTtype ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = StateT Token (ErrorT ErrorMsg m)</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token a</p><p>27 / 34</p></li><li><p>Adding session: StateTtype ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = StateT Token (ErrorT ErrorMsg m)</p><p>run :: Token RestT m a Result m arun t x = runErrorT $ evalStateT x t</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token a</p><p>27 / 34</p></li><li><p>Adding session: StateTtype ErrorMsg = Stringtype Token = Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = StateT Token (ErrorT ErrorMsg m)</p><p>run :: Token RestT m a Result m arun t x = runErrorT $ evalStateT x t</p><p>liftRest :: m a RestT m aliftRest = lift . lift</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token a</p><p>27 / 34</p></li><li><p>Dependency injection: ReaderTtype ErrorMsg = Stringtype Token = Stringtype Getter m = String m Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token</p><p>.ReaderT (Getter m) a</p><p>28 / 34</p></li><li><p>Dependency injection: ReaderTtype ErrorMsg = Stringtype Token = Stringtype Getter m = String m Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))</p><p>run :: Getter m Token RestT m a Result m arun g t x = runErrorT $ evalStateT (runReaderT x g) t</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token</p><p>.ReaderT (Getter m) a</p><p>28 / 34</p></li><li><p>Dependency injection: ReaderTtype ErrorMsg = Stringtype Token = Stringtype Getter m = String m Stringtype Result m a = m (Either ErrorMsg a)</p><p>type RestT m = ReaderT (Getter m) (StateT Token (ErrorT ErrorMsg m))</p><p>run :: Getter m Token RestT m a Result m arun g t x = runErrorT $ evalStateT (runReaderT x g) t</p><p>liftRest :: m a RestT m aliftRest = lift . lift . lift</p><p>..</p><p>m</p><p>.ErrorT ErrorMsg</p><p>.StateT Token</p><p>.ReaderT (Getter m) a</p><p>28 / 34</p></li><li><p>YAY!</p><p>request :: String RestT m Stringrequest method = do</p><p>getter asktoken get</p><p>let q = query method tokenliftRest $ getter q</p><p>29 / 34</p></li><li><p>AT LAST!</p><p>authenticate :: RestT m ()authenticate = do</p><p>token getunless (null token)</p><p>(throwError "already logged in")answer request "getToken"</p><p>token parse answerput token</p><p>30 / 34</p></li><li><p>WOOOO!</p><p>main = void $ run httpGet emptyToken $ doauthenticateanswer request "showMyStuff"liftIO $ print answer</p><p>31 / 34</p></li><li><p>Outline</p><p>I MonadsI Our missionI TransformersI Building RestTI Wrapping up!</p><p>32 / 34</p></li><li><p>What have we learned today?</p><p>I Transformers: stack monads.I Combine their powers!I Hide stack details.</p><p>33 / 34</p></li><li><p>This is the end. You are free.</p><p>Thank you.Any questions?</p><p>34 / 34</p><p>MonadsOur missionTransformersBuilding RestTWrapping up</p></li></ul>