advanced functional programming tim sheard 1 lecture 6 advanced functional programming tim sheard...
DESCRIPTION
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)TRANSCRIPT
Advanced Functional Programming
Tim Sheard 1Lecture 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
Advanced Functional Programming
Tim Sheard 2Lecture 6
Monad Transfor
mers
A Monad is an ADTAn 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 systemHigher order type constructorsRank2 (local) polymorphism
Advanced Functional Programming
Tim Sheard 3Lecture 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 argumentMon : * -> *
Each component of the pair which is the argument to Mon is a polymorphic function.(forall a . a -> m a)
Advanced Functional Programming
Tim Sheard 4Lecture 6
Transfor
mers
type Transformer s t = Mon s -> Mon t
transform :: Mon S -> Mon T
The type T probably mentions S
Advanced Functional Programming
Tim Sheard 5Lecture 6
Three monad
s
--Iddata Id x = Id x
--Envdata Env e x = Env (e -> x)
--Statedata State s x = State (s -> (x,s))
Advanced Functional Programming
Tim Sheard 6Lecture 6
Id monad
data Id x = Id x
idMon :: Mon IdidMon = let bind x f = case x of {(Id y) -> f y } bind (Id y) f = f y in Mon Id bind
runId :: Id a -> arunId (Id x) = x
Advanced Functional Programming
Tim Sheard 7Lecture 6
Env monaddata 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)
Advanced Functional Programming
Tim Sheard 8Lecture 6
State Monaddata 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))
Advanced Functional Programming
Tim Sheard 9Lecture 6
Env Transfor
mer
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)
Advanced Functional Programming
Tim Sheard 10Lecture 6
The transfor
mer
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)
Advanced Functional Programming
Tim Sheard 11Lecture 6
The State Transfor
merdata 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)
Advanced Functional Programming
Tim Sheard 12Lecture 6
The transfor
mer
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)
Advanced Functional Programming
Tim Sheard 13Lecture 6
An exampl
e
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.
Advanced Functional Programming
Tim Sheard 14Lecture 6
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>));
Advanced Functional Programming
Tim Sheard 15Lecture 6
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;
Advanced Functional Programming
Tim Sheard 16Lecture 6
State transfor
mer 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)>);
Advanced Functional Programming
Tim Sheard 17Lecture 6
An exampl
e-| 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));
Advanced Functional Programming
Tim Sheard 18Lecture 6
-| 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>
Advanced Functional Programming
Tim Sheard 19Lecture 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.
Advanced Functional Programming
Tim Sheard 20Lecture 6
From IxEnvMT.hs
newtype WithEnv e m a = E { unE :: e -> m a }
withEnv :: e -> WithEnv e m a -> m awithEnv 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))
Advanced Functional Programming
Tim Sheard 21Lecture 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
Advanced Functional Programming
Tim Sheard 22Lecture 6
IxStateMT.hs
newtype WithState s m a = S { ($$) :: s -> m (a,s) }
withSt :: Monad m => s -> WithState s m a -> m awithSt 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 amapState inF outF (S m) = S (liftM outF' . m . inF) where outF' (a,s) = (a, outF s)
Advanced Functional Programming
Tim Sheard 23Lecture 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)
Advanced Functional Programming
Tim Sheard 24Lecture 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
Advanced Functional Programming
Tim Sheard 25Lecture 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
Advanced Functional Programming
Tim Sheard 26Lecture 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
Advanced Functional Programming
Tim Sheard 27Lecture 6
HasStateclass 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
Advanced Functional Programming
Tim Sheard 28Lecture 6
Example use -- Interpreter
Syntax
type Name = Stringtype Message = Stringdata 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
Advanced Functional Programming
Tim Sheard 29Lecture 6
The eval functioneval (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 xeval (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 =<< getSteval (WriteRef x e) = do v <- eval e updSt_ $ \s -> (x,v) : filter ((/= x) . fst) s return 0eval (e1 :> e2) = eval e1 >> eval e2
Advanced Functional Programming
Tim Sheard 30Lecture 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
Advanced Functional Programming
Tim Sheard 31Lecture 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 )))
Advanced Functional Programming
Tim Sheard 32Lecture 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
Advanced Functional Programming
Tim Sheard 33Lecture 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 arun m = do x <- removeExcept $ listOutput $ withEnv [] $
withSt [] m case x of Left err -> error ("error: " ++ err) Right (v,o) -> mapM putStrLn o >> return v
Advanced Functional Programming
Tim Sheard 34Lecture 6
Advanced Features
Multiple occurences of Env, State, etc.