Download presentation
Presentation is loading. Please wait.
Published byAnna Small Modified over 8 years ago
1
Advanced Functional Programming Tim Sheard 1 Lecture 6 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
Advanced Functional Programming Tim Sheard 2 Lecture 6 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
Advanced Functional Programming Tim Sheard 3 Lecture 6 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
Advanced Functional Programming Tim Sheard 4 Lecture 6 Transformers type Transformer s t = Mon s -> Mon t transform :: Mon S -> Mon T The type T probably mentions S
5
Advanced Functional Programming Tim Sheard 5 Lecture 6 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
Advanced Functional Programming Tim Sheard 6 Lecture 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
Advanced Functional Programming Tim Sheard 7 Lecture 6 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
Advanced Functional Programming Tim Sheard 8 Lecture 6 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
Advanced Functional Programming Tim Sheard 9 Lecture 6 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
Advanced Functional Programming Tim Sheard 10 Lecture 6 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
Advanced Functional Programming Tim Sheard 11 Lecture 6 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
Advanced Functional Programming Tim Sheard 12 Lecture 6 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
Advanced Functional Programming Tim Sheard 13 Lecture 6 An example 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) The problem is that the functions on the inner monad are not lifted. We can use Haskell Classes to fix this.
14
Advanced Functional Programming Tim Sheard 14 Lecture 6 Making transformers “visible” in MetaML datatype ('M : * -> * ) Monad2 = Mon2 of (['a]. 'a 'M>) * (['a,'b]. ('a -> 'b 'M) -> 'b 'M>); val id2 = (Mon2 (, fn f => let val (Id y) = x in f y end>));
15
Advanced Functional Programming Tim Sheard 15 Lecture 6 Env transformer at the code level fun TransEnv2 (Mon2(unitM,bindM)) = let val unitEnv = Tenv(fn rho => ~unitM x)> in Mon2(unitEnv, fn f => Tenv(fn rho => let val (Tenv h) = x in ~(force (force bindM ) let val (Tenv g) = f a in g rho end> ) end)>) end;
16
Advanced Functional Programming Tim Sheard 16 Lecture 6 State transformer at code level fun TransStore2 (Mon2(unitM,bindM)) = Mon2 ( Tstore(fn sigma => ~unitM (x,sigma))>, fn f => Tstore(fn sigma0 => let val (Tstore h) = x in ~(force (force bindM ) let val (a,sigma1) = w val (Tstore g) = f a in g sigma1 end> ) end)>);
17
Advanced Functional Programming Tim Sheard 17 Lecture 6 An example -| fun bindof (Mon2(x,y)) = y; val bindof = Fn : ['a,'b,'c]. 'c Monad2 -> ('b -> 'a 'c ) -> 'a 'c > val ans = bindof(TransStore2 (TransEnv2 id2));
18
Advanced Functional Programming Tim Sheard 18 Lecture 6 -| val ans = (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 -> ('4,'2,('1,Id) Tenv) Tstore) -> ('4,'2,('1,Id) Tenv) Tstore>
19
Advanced Functional Programming Tim Sheard 19 Lecture 6 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
Advanced Functional Programming Tim Sheard 20 Lecture 6 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
Advanced Functional Programming Tim Sheard 21 Lecture 6 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
Advanced Functional Programming Tim Sheard 22 Lecture 6 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
Advanced Functional Programming Tim Sheard 23 Lecture 6 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
Advanced Functional Programming Tim Sheard 24 Lecture 6 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
Advanced Functional Programming Tim Sheard 25 Lecture 6 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
Advanced Functional Programming Tim Sheard 26 Lecture 6 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
Advanced Functional Programming Tim Sheard 27 Lecture 6 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
Advanced Functional Programming Tim Sheard 28 Lecture 6 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
Advanced Functional Programming Tim Sheard 29 Lecture 6 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
Advanced Functional Programming Tim Sheard 30 Lecture 6 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
Advanced Functional Programming Tim Sheard 31 Lecture 6 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
Advanced Functional Programming Tim Sheard 32 Lecture 6 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
Advanced Functional Programming Tim Sheard 33 Lecture 6 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 Functional Programming Tim Sheard 34 Lecture 6 Advanced Features Multiple occurences of Env, State, etc.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.