1
1
mirror of https://github.com/thma/LtuPatternFactory.git synced 2024-12-12 10:42:08 +03:00

adding MonadState example

This commit is contained in:
thma 2018-12-30 22:07:48 +01:00
parent 4c5492ede5
commit b52d8be513
2 changed files with 21 additions and 8 deletions

View File

@ -850,12 +850,13 @@ eval (Let x e1 e2) = eval e1 >>= \v -> -- bind the result of (eval
local ((x,v):) (eval e2) -- add (x,v) to the env, eval e2 in the extended env local ((x,v):) (eval e2) -- add (x,v) to the env, eval e2 in the extended env
``` ```
The interesting part here is the helper function `local f m` which applies `f` to the environment and then executes `m` against the (locally) changed environment: The interesting part here is the helper function `local f m` which applies `f` to the environment and then executes `m` against the (locally) changed environment.
Providing a locally modified environment as the scope of the evaluation of `e2` is exactly what the `let` binding intends:
```haskell ```haskell
-- | Executes a computation in a modified environment. -- | Executes a computation in a modified environment.
local :: (r -> r) -- ^ The function to modify the environment. local :: (r -> r) -- ^ The function to modify the environment.
-> m a -- ^ @Reader@ to run in the modified environment. -> m a -- ^ @Reader@ to run in the modified environment.
-> m a -> m a
instance MonadReader r ((->) r) where instance MonadReader r ((->) r) where
@ -872,12 +873,26 @@ interpreterDemo = do
(BinOp (*) (Val 2) (Var "x")) (BinOp (*) (Val 2) (Var "x"))
print $ runReader (eval exp1) env print $ runReader (eval exp1) env
-- an the in GHCi: -- an then in GHCi:
> interpreterDemo > interpreterDemo
18 18
``` ```
By virtue of the `local` function we used `MonadReader` as if it provided modifiable state. So for many use cases that require only *local* state modifications its not required to use the somewhat more tricky `MonadState`.
Writing the interpreter function with a `MonadState` looks like follows:
```haskell
eval1 :: (MonadState (Env a) m) => Exp a -> m a
eval1 (Val i) = return i
eval1 (Var x) = gets (fetch x)
eval1 (BinOp op e1 e2) = liftM2 op (eval1 e1) (eval1 e2)
eval1 (Let x e1 e2) = eval1 e1 >>= \v ->
modify ((x,v):) >>
eval1 e2
```
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/). 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/).
[Sourcecode for this section](https://github.com/thma/LtuPatternFactory/blob/master/src/Interpreter.hs) [Sourcecode for this section](https://github.com/thma/LtuPatternFactory/blob/master/src/Interpreter.hs)

View File

@ -31,8 +31,8 @@ eval (Let x e1 e2) = eval e1 >>= \v -> local ((x,v):) (eval e2)
-- using a State Monad to thread the environment. The Environment can be accessed by get, gets, modify. -- using a State Monad to thread the environment. The Environment can be accessed by get, gets, modify.
eval1 :: (MonadState (Env a) m) => Exp a -> m a eval1 :: (MonadState (Env a) m) => Exp a -> m a
eval1 (Var x) = gets (fetch x)
eval1 (Val i) = return i eval1 (Val i) = return i
eval1 (Var x) = gets (fetch x)
eval1 (BinOp op e1 e2) = liftM2 op (eval1 e1) (eval1 e2) eval1 (BinOp op e1 e2) = liftM2 op (eval1 e1) (eval1 e2)
eval1 (Let x e1 e2) = eval1 e1 >>= \v -> modify ((x,v):) >> eval1 e2 eval1 (Let x e1 e2) = eval1 e1 >>= \v -> modify ((x,v):) >> eval1 e2
@ -49,11 +49,9 @@ interpreterDemo = do
print $ eval exp env print $ eval exp env
print $ runReader (eval exp) env print $ runReader (eval exp) env
print $ evalState (eval1 exp) env print $ runState (eval1 exp) env
let exp1 = Let "x" let exp1 = Let "x" (BinOp (+) (Val 4) (Val 5)) (BinOp (*) (Val 2) (Var "x"))
(BinOp (+) (Val 4) (Val 5))
(BinOp (*) (Val 2) (Var "x"))
print $ eval exp1 [] print $ eval exp1 []
putStrLn "" putStrLn ""