diff --git a/README.md b/README.md index fe18860..99d19b5 100644 --- a/README.md +++ b/README.md @@ -777,12 +777,46 @@ Next we define an evaluator function that pattern matches the above expression A ```haskell eval :: MonadReader (Env a) m => Exp a -> m a -eval (Var x) = asks (fetch x) eval (Val i) = return i +eval (Var x) = asks (fetch x) eval (BinOp op e1 e2) = liftM2 op (eval e1) (eval e2) eval (Let x e1 e2) = eval e1 >>= \v -> local ((x,v):) (eval e2) ``` +Let's explore this dense code line by line. + +```haskell +eval :: MonadReader (Env a) m => Exp a -> m a +``` + +The most simple instance for `MonadReader` is the partially applied function type `((->) env)`. +Let's assume the compiler will choose this type as the `MonadReader` instance. We can then rewrite the function signature as follows: + +```haskell +eval :: Exp a -> ((->) (Env a)) a -- expanding m to ((->) (Env a)) +eval :: Exp a -> Env a -> a -- applying infix notation for (->) +``` + +This is exactly the signature we were using for the `Applicative` eval function which matches our original intent to eval an expression of type `Exp a` in an environment of type `Env a` to a result of type `a`. + +```haskell +eval (Val i) = return i +``` + +In this line we are pattern matching for a `(Val i)`. The atomic value `i` is `return`ed, that is lifted to a value of the type `Env a -> a`. + +```haskell +eval (Var x) = asks (fetch x) +``` + +`asks` is a helper function that applies its argument `f :: env -> a` (in our case `(fetch x)` that is lookup of variable `x`) to the environment. It's thus typically used to handle environment lookups: + +```haskell +asks :: (MonadReader env m) => (env -> a) -> m a +asks f = ask >>= return . f +``` + + [to be continued] This section was inspired by ideas presented in [Quick Interpreters with the Reader Monad](https://donsbot.wordpress.com/2006/12/11/quick-interpreters-with-the-reader-monad/). diff --git a/src/Interpreter.hs b/src/Interpreter.hs index a0455e7..2915e5b 100644 --- a/src/Interpreter.hs +++ b/src/Interpreter.hs @@ -14,9 +14,12 @@ type BinOperator a = a -> a -> a type Env a = [(String, a)] -- using a Reader Monad to thread the environment. The Environment can be accessed by ask and asks. ---eval :: Exp a => Exp a -> Env a -> a -eval :: MonadReader (Env a) m => Exp a -> m a -eval (Var x) = asks (fetch x) +--eval :: Exp a -> Env a -> a +eval :: Exp a -> ((->) (Env a)) a +--eval :: MonadReader (Env a) m => Exp a -> m a +-- Exp a -> ((->) Env a) a +-- Exp a -> Env a -> a +eval (Var x) = ask >>= return . (fetch x) --asks (fetch x) eval (Val i) = return i eval (BinOp op e1 e2) = liftM2 op (eval e1) (eval e2) eval (Let x e1 e2) = eval e1 >>= \v -> local ((x,v):) (eval e2) @@ -46,7 +49,7 @@ interpreterDemo = do (BinOp (*) (Var "pi") (Var "x")) env = [("pi", pi)] print $ eval exp env - print $ runReader (eval exp) env + --print $ runReader (eval exp) env print $ evalState (eval1 exp) env