-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathInterpreter.hs
63 lines (51 loc) · 2.04 KB
/
Interpreter.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
{-# LANGUAGE FlexibleContexts #-}
module Interpreter where
import Control.Monad.Reader
import Control.Monad.State
data Exp a =
Var String
| BinOp (BinOperator a) (Exp a) (Exp a)
| Let String (Exp a) (Exp a)
| Val a
type BinOperator a = a -> a -> a
type Env a = [(String, a)]
-- environment lookup
fetch :: String -> Env a -> a
fetch x [] = error $ "variable " ++ x ++ " is not defined"
fetch x ((y,v):ys)
| x == y = v
| otherwise = fetch x ys
-- using a Reader Monad to thread the environment. The Environment can be accessed by ask and asks.
--eval :: Exp a -> Env a -> a
--eval :: Exp a -> ((->) (Env a)) a
eval :: MonadReader (Env a) m => Exp a -> m a
eval (Var 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)
eval' :: Exp a -> Reader (Env a) a
eval' (Var 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)
-- 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 (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
letExp = Let "x"
(Let "y"
(BinOp (+) (Val 5) (Val 7))
(BinOp (/) (Var "y") (Val 6)))
(BinOp (*) (Var "pi") (Var "x"))
interpreterDemo :: IO ()
interpreterDemo = do
putStrLn "Interpreter -> Reader Monad + ADTs + pattern matching"
let env = [("pi", pi)]
print $ eval letExp env
print $ runReader (eval letExp) env
print $ runState (eval1 letExp) env
let exp1 = Let "x" (BinOp (+) (Val 4) (Val 5)) (BinOp (*) (Val 2) (Var "x"))
print $ eval exp1 []
putStrLn ""