Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
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 Lecture 6 Tim Sheard 1 Advanced Functional Programming 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 Lecture 6 Tim Sheard 2 Advanced Functional Programming 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) Lecture 6 Tim Sheard 3 Advanced Functional Programming Transformers type Transformer s t = Mon s -> Mon t transform :: Mon S -> Mon T The type T probably mentions S Lecture 6 Tim Sheard 4 Advanced Functional Programming 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)) Lecture 6 Tim Sheard 5 Advanced Functional Programming 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 Lecture 6 Tim Sheard 6 Advanced Functional Programming 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) Lecture 6 Tim Sheard 7 Advanced Functional Programming 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)) Lecture 6 Tim Sheard 8 Advanced Functional Programming 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) Lecture 6 Tim Sheard 9 Advanced Functional Programming 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) Lecture 6 Tim Sheard 10 Advanced Functional Programming 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) Lecture 6 Tim Sheard 11 Advanced Functional Programming 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) Lecture 6 Tim Sheard 12 Advanced Functional Programming 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) Lecture 6 Tim Sheard 13 Advanced Functional Programming 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>)); Lecture 6 Tim Sheard 14 Advanced Functional Programming 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; Lecture 6 Tim Sheard 15 Advanced Functional Programming 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)>); Lecture 6 Tim Sheard 16 Advanced Functional Programming 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)); Lecture 6 Tim Sheard 17 Advanced Functional Programming -| 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> Lecture 6 Tim Sheard 18 Advanced Functional Programming 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. Lecture 6 Tim Sheard 19 Advanced Functional Programming 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)) Lecture 6 Tim Sheard 20 Advanced Functional Programming 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 Lecture 6 Tim Sheard 21 Advanced Functional Programming 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) Lecture 6 Tim Sheard 22 Advanced Functional Programming 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) Lecture 6 Tim Sheard 23 Advanced Functional Programming 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 Lecture 6 Tim Sheard 24 Advanced Functional Programming 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 Lecture 6 Tim Sheard 25 Advanced Functional Programming HasEnv class Monad where getEnv inEnv inModEnv m => HasEnv m ix e | m ix -> e :: ix -> m e :: ix -> e -> m a -> m a :: ix -> (e -> e) -> m a -> m a inEnv ix e inModEnv ix f m = inModEnv ix (const e) = do { e <- getEnv ix ; inEnv ix (f e) m } -- define at least one of: -- * getEnv, inEnv -- * getEnv, inModEnv Lecture 6 Tim Sheard 26 Advanced Functional Programming 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 setSt ix getSt ix = do s <- getSt ix; setSt ix (f s) = updSt ix . const = 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 Lecture 6 Tim Sheard 27 Advanced Functional Programming Example use -- Interpreter Syntax type Name type Message data E Lecture 6 = String = String = 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 Tim Sheard 28 Advanced Functional Programming The eval function eval eval eval eval (e1 (e1 (e1 (e1 :+: :-: :*: :/: e2) e2) e2) e2) eval (Int x) eval (Let x e1 e2) eval (Var x) return) . eval (Print x e) eval (ReadRef x) eval (WriteRef x e) eval (e1 :> e2) Lecture 6 = = = = liftM2 (+) (eval e1) (eval e2) liftM2 (-) (eval e1) (eval e2) liftM2 (*) (eval e1) (eval e2) liftM2 div (eval e1) $ (do x <- eval e2 when (x == 0) (raise "division by 0") return x) = return x = do v <- eval e1; inModEnv ((x,v):) (eval e2) = (maybe (raise ("undefined variable: " ++ x)) (lookup x =<< getEnv) = do v <- eval e output (x ++ show v) return v = maybe (return 0) return . lookup x =<< getSt = do v <- eval e updSt_ $ \s -> (x,v) : filter ((/= x) . fst) s return 0 = eval e1 >> eval e2 Tim Sheard 29 Advanced Functional Programming 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 Lecture 6 Tim Sheard 30 Advanced Functional Programming What Monad has all these? type Heap type Env type M Lecture 6 = [(Name,Int)] = [(Name,Int)] = WithState Heap ( WithEnv Env ( WithOutput String ( WithExcept String IO ))) Tim Sheard 31 Advanced Functional Programming 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 Lecture 6 Tim Sheard 32 Advanced Functional Programming 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 Lecture 6 Tim Sheard 33 Advanced Functional Programming Advanced Features Multiple occurences of Env, State, etc. Lecture 6 Tim Sheard 34