1 / 34

Advanced Functional Programming

Advanced Functional Programming. Tim Sheard Oregon Graduate Institute of Science & Technology. Lecture 7: Monad Transformers Monads as a data structure Transformers as functions Visualizing Transforms (using MetaML) Transformers as classes. Monad Transformers. A Monad is an ADT

coy
Download Presentation

Advanced Functional Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Advanced Functional Programming • Tim Sheard • Oregon Graduate Institute of Science & Technology • Lecture 7: Monad Transformers • Monads as a data structure • Transformers as functions • Visualizing Transforms (using MetaML) • Transformers as classes

  2. Monad Transformers • A Monad is an ADT • An ADT is a collection of related (typed) functions that interface some data. • A Monad Transformer is a function from one monad ADT to another. • In order to type a monad transformer we need 2 extensions to Haskell’s type system • Higher order type constructors • Rank2 (local) polymorphism

  3. Recall definition of monad • data Mon m = • Mon (forall a . a -> m a) • (forall a b . m a -> (a -> m b) -> m b) • Monad is a type constructor that takes another type constructor as an argument • Mon : * -> * • Each component of the pair which is the argument to Mon is a polymorphic function. • (forall a . a -> m a)

  4. Transformers • type Transformer s t = • Mon s -> Mon t • transform :: Mon S -> Mon T • The type T probably mentions S

  5. Three monads • --Id • data Id x = Id x • --Env • data Env e x = Env (e -> x) • --State • data State s x = State (s -> (x,s))

  6. Id monad • data Id x = Id x • idMon :: Mon Id • idMon = • let bind x f = case x of {(Id y) -> f y } • bind (Id y) f = f y • in Mon Id bind • runId :: Id a -> a • runId (Id x) = x

  7. Env monad • data Env e x = Env (e -> x) • envMon :: Mon (Env e) • envMon = • let unit x = Env(\ _ -> x) • bind (Env g) f = • Env(\ e -> case f(g e) of • Env h -> h e) • in Mon unit bind • readEnv = Env(\ e -> e) • inEnv e (Env f) = Env(\ e2 -> f e)

  8. State Monad • data State s x = State (s -> (x,s)) • stateMon :: Mon (State s) • stateMon = • let unit x = State(\ s -> (x,s)) • bind (State g) f = • State(\ s -> let (a,s') = g s • State h = f a • in h s') • in Mon unit bind • readSt = State(\ s -> (s,s)) • writeSt x = State(\ s -> ((),x))

  9. Env Transformer • data WithEnv env m a = WithEnv (env -> m a) • m is the old monad • env is the type of the env being added to m • Also need to lift old computations and the function rdEnv and inEnv • data Fenv m = Fenv • (forall a e . m a -> WithEnv e m a) • (forall e . WithEnv e m e) • (forall a e . • e -> WithEnv e m a -> WithEnv e m a)

  10. The transformer • transEnv :: Mon m -> (Mon (WithEnv e m),Fenv m) • transEnv (Mon unitM bindM) = • let unitEnv x = WithEnv(\ rho -> unitM x) • bindEnv x f = • WithEnv(\ rho -> • let (WithEnv h) = x • in bindM (h rho) • (\ a -> let (WithEnv g) = f a • in g rho)) • lift2 x = WithEnv(\ rho -> x) • rdEnv = WithEnv(\ rho -> unitM rho) • inEnv rho (WithEnv x) = WithEnv(\ _ -> x rho) • in (Mon unitEnv bindEnv,Fenv lift2 rdEnv inEnv)

  11. The State Transformer • data WithStore s m a = • WithStore (s -> m (a,s)) • data Fstore m = Fstore • (forall a s . m a -> WithStore s m a) • (forall s . (s -> s) -> WithStore s m ()) • (forall s . WithStore s m s)

  12. The transformer • transStore :: Mon m -> (Mon (WithStore s m),Fstore m) • transStore (Mon unitM bindM) = • let unitStore x = WithStore(\sigma -> unitM(x,sigma)) • bindStore x f = • WithStore(\ sigma0 -> • let (WithStore h) = x • in bindM (h sigma0) • (\ (a,sigma1) -> • let (WithStore g) = f a • in g sigma1 ) ) • lift2 x = WithStore(\ sigma -> • bindM x (\ y -> unitM(y,sigma))) • update f = WithStore(\ sigma -> unitM((),f sigma)) • get = WithStore(\sigma -> unitM(sigma,sigma)) • in (Mon unitStore bindStore,Fstore lift2 update get)

  13. An example The problem is that the functions on the inner monad are not lifted. We can use Haskell Classes to fix this. • ex1 :: (Mon (WithStore a (WithEnv b Id)) • ,Fenv Id • ,Fstore (WithEnv c Id)) • ex1 = let (mon1,funs1) = transEnv idMon • (mon2,funs2) = transStore mon1 • in (mon2,funs1,funs2)

  14. Making transformers “visible” in MetaML • datatype ('M : * -> * ) Monad2 = • Mon2 of • (['a]. <'a -> 'a 'M>) * • (['a,'b]. <'a 'M -> ('a -> 'b 'M) -> 'b 'M>); • val id2 = • (Mon2 (<Id>, • <fn x => fn f => • let val (Id y) = x in f y end>));

  15. Env transformer at the code level • fun TransEnv2 (Mon2(unitM,bindM)) = • let val unitEnv = • <fn x => Tenv(fn rho => ~unitM x)> • in Mon2(unitEnv, • <fn x => fn f => • Tenv(fn rho => • let val (Tenv h) = x • in ~(force (force bindM <h rho>) • <fn a => • let val (Tenv g) = f a • in g rho end> • ) end)>) end;

  16. State transformer at code level • fun TransStore2 (Mon2(unitM,bindM)) = • Mon2 • (<fn x => Tstore(fn sigma => ~unitM (x,sigma))>, • <fn x => fn f => • Tstore(fn sigma0 => • let val (Tstore h) = x • in ~(force (force bindM <h sigma0>) • <fn w => let val (a,sigma1) = w • val (Tstore g) = f a • in g sigma1 end> • ) • end)>);

  17. An example • -| fun bindof (Mon2(x,y)) = y; • val bindof = Fn : ['a,'b,'c]. • 'c Monad2 -> <'b 'c -> ('b -> 'a 'c ) -> 'a 'c > • val ans = • bindof(TransStore2 (TransEnv2 id2));

  18. -| val ans = • <(fn a => • (fn b => • Tstore • (fn c => • let val Tstore d = a • in Tenv • (fn e => • let val Tenv f = d c • val Id g = f e • val (i,h) = g • val Tstore j = b i • val Tenv k = j h • in k e end) end)))> • : <('3 ,'2 ,('1 ,Id) Tenv) Tstore -> • ('3 -> ('4 ,'2 ,('1 ,Id) Tenv) Tstore) -> • ('4 ,'2 ,('1 ,Id) Tenv) Tstore>

  19. Using Haskell Classes • This part of the lecture is based upon the Monad library developed (in part) by Iavor Diatchki. • Uses classes instead of data stuctures to encode monads. • Instances then are used to encode monad transformers.

  20. From IxEnvMT.hs • newtype WithEnv e m a = • E { unE :: e -> m a } • withEnv :: e -> WithEnv e m a -> m a • withEnv e (E f) = f e • mapEnv :: Monad m => (e2 -> e1) -> WithEnv e1 m a -> WithEnv e2 m a • mapEnv f (E m) = E (\e -> m (f e))

  21. From IxEnvMT.hs cont. • instance Monad m => • Functor (WithEnv e m) where • fmap = liftM • instance Monad m => • Monad (WithEnv e m) where • return = lift . return • E m >>= f = E (\e -> do { x <- m e • ; unE (f x) e }) • E m >> n = E (\e -> m e >> withEnv e n) • fail = lift . fail

  22. IxStateMT.hs • newtype WithState s m a = • S { ($$) :: s -> m (a,s) } • withSt :: Monad m => s -> WithState s m a -> m a • withSt s = liftM fst . withStS s • withStS :: s -> WithState s m a -> m (a,s) • withStS s (S f) = f s • mapState :: Monad m => • (t -> s) -> (s -> t) -> • WithState s m a -> WithState t m a • mapState inF outF (S m) = S (liftM outF' . m . inF) • where outF' (a,s) = (a, outF s)

  23. IxStateMT.hs continued • instance Monad m => Functor (WithState s m) where • fmap = liftM • instance Monad m => Monad (WithState s m) where • return x = S (\s -> return (x,s)) • S m >>= f = S (\s -> m s >>= \(a,s') -> f a $$ s') • fail msg = S (\s -> fail msg)

  24. To lift from one monad to another • Add a new class for monad transformers • class MT t where • lift :: (Monad m, Monad (t m)) => • m a -> t m a

  25. Add instance for each Transformer • instance MT (WithState s) where • lift m = • S (\s -> do a <- m; return (a,s)) • instance MT (WithEnv e) where • lift = E . Const • Each Transformer also supports a class of operations – the HasXX classes

  26. HasEnv • class Monad m => HasEnv m ix e | m ix -> e where • getEnv :: ix -> m e • inEnv :: ix -> e -> m a -> m a • inModEnv :: ix -> (e -> e) -> m a -> m a • inEnv ix e = inModEnv ix (const e) • inModEnv ix f m = do { e <- getEnv ix • ; inEnv ix (f e) m } • -- define at least one of: • -- * getEnv, inEnv • -- * getEnv, inModEnv

  27. HasState • class Monad m => HasState m ix s | m ix -> s where • updSt :: ix -> (s -> s) -> m s -- returns the old state • updSt_ :: ix -> (s -> s) -> m () • getSt :: ix -> m s • setSt :: ix -> s -> m s -- returns the old state • setSt_ :: ix -> s -> m () • updSt ix f = do s <- getSt ix; setSt ix (f s) • setSt ix = updSt ix . const • getSt ix = updSt ix id • updSt_ ix f = do updSt ix f; return () • setSt_ ix s = do setSt ix s; return () • -- define at least one of: • -- * updSt • -- * getSt, setSt

  28. Example use -- Interpreter • Syntax • type Name = String • type Message = String • data E = E :+: E | E :-: E | • E :*: E | E :/: E | Int Int • | Let Name E E | Var Name • | Print Message E • | ReadRef Name • | WriteRef Name E • | E :> E

  29. The eval function • eval (e1 :+: e2) = liftM2 (+) (eval e1) (eval e2) • eval (e1 :-: e2) = liftM2 (-) (eval e1) (eval e2) • eval (e1 :*: e2) = liftM2 (*) (eval e1) (eval e2) • eval (e1 :/: e2) = liftM2 div (eval e1) $ • (do x <- eval e2 • when (x == 0) (raise "division by 0") • return x) • eval (Int x) = return x • eval (Let x e1 e2) = do v <- eval e1; inModEnv ((x,v):) (eval e2) • eval (Var x) = (maybe (raise ("undefined variable: " ++ x)) return) . • (lookup x =<< getEnv) • eval (Print x e) = do v <- eval e • output (x ++ show v) • return v • eval (ReadRef x) = maybe (return 0) return . lookup x =<< getSt • eval (WriteRef x e) = do v <- eval e • updSt_ $ \s -> (x,v) : filter ((/= x) . fst) s • return 0 • eval (e1 :> e2) = eval e1 >> eval e2

  30. The Type of Eval • eval :: • (HasState a Z [([Char],Int)], • HasOutput a Z [Char], • HasEnv a Z [([Char],Int)], • HasExcept a [Char]) => • E -> a Int

  31. What Monad has all these? • type Heap = [(Name,Int)] • type Env = [(Name,Int)] • type M = WithState Heap • ( WithEnv Env • ( WithOutput String • ( WithExcept String IO • )))

  32. instance Monad m => HasEnv (WithEnv e m) Z e where • getEnv _ = E return • inModEnv _ = mapEnv • instance HasEnv m ix e => HasEnv (WithEnv e' m) (S ix) e where • getEnv (Next ix) = lift (getEnv ix) • inModEnv (Next ix) f m = E (\e -> inModEnv ix f (withEnv e m)) • instance HasState m ix s => HasState (WithEnv e m) ix s where • updSt ix = lift . updSt ix • instance HasOutput m ix o => HasOutput (WithEnv e m) ix o where • outputTree ix = lift . outputTree ix

  33. Run for the monad • Then run for the monad is the code that actually specifies how the pieces are put together! • run :: M a -> IO a • run m = • do x <- removeExcept $ listOutput $ withEnv [] $ withSt [] m • case x of • Left err -> error ("error: " ++ err) • Right (v,o) -> mapM putStrLn o >> return v

  34. Advanced Features • Multiple occurences of Env, State, etc.

More Related