import Control.Monad.Reader data Bound = Int Int | Fun (Reader Env Int -> Reader Env Int) type Env = Char -> Bound env0 = \var -> error "Not found" insert var value e = \sought -> if sought == var then value else e sought getint :: Char -> Reader Env Int getint var = asks (\e -> let (Int x) = e var in x) getfun :: Char -> Reader Env (Reader Env Int -> Reader Env Int) getfun var = asks (\e -> let (Fun f) = e var in f) -- monadic versions of `x` and `y` and `f` getx = getint 'x' gety = getint 'y' getf = getfun 'f' -- monadic version of `y + x` expr1 :: Reader Env Int expr1 = liftM2 (+) gety getx -- monadic version of `\y -> y + x` lambda1 :: Reader Env (Reader Env Int -> Reader Env Int) lambda1 = return (\yy -> yy >>= \y -> local (insert 'y' (Int y)) expr1) letx xx body = xx >>= \x -> local (insert 'x' (Int x)) body letf ff body = ff >>= \f -> local (insert 'f' (Fun f)) body -- monadic version of `let x = 2 in let f = \y -> y + x in f 3` expr4 :: Reader Env Int expr4 = letx (return 2) (letf lambda1 (getf >>= \f -> f (return 3))) res = runReader expr4 env0 -- will be 5