-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEval.hs
80 lines (66 loc) · 2.42 KB
/
Eval.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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
module Eval (call, eval1, def2let) where
import Prelude.Extra
import Data.List (sortOn)
import qualified Data.Map.Strict as Map
import Syntax
isExpr :: Stmt -> Bool
isExpr = \case
Expr _ -> True
Def _ _ -> False
TypeDecl _ -> False
def2let :: [Stmt] -> Either Text (Typed Expr)
def2let exprs = go [] $ sortOn isExpr exprs
where
go pairs = \case
[] -> Left "need at least one expr"
[Expr e] -> let (t, _) = extractType e in Right $ mkTyped t $ LetRec pairs e
(Expr _) : _ -> Left $ "can only have one expr" <> tshow exprs
(Def n1 e1) : e -> go ((n1, e1):pairs) e
(TypeDecl _) : e -> go pairs e
eval1 :: Env -> Expr -> Either Text Val
eval1 env@(Env syms) = elimThunk <=< \case
Val x -> Right x
Var x -> case Map.lookup x syms of
Nothing -> Left $ "no such var: " <> tshow x
Just v -> Right v
Let [] expr -> eval1 env (rmType expr)
Let ((n, e):bs) expr -> do
v <- eval1 env (rmType e)
eval1 (Env $ Map.insert (rmType n) v syms) (Let bs expr)
LetRec bindings expr -> do
let thunks = flip map bindings $
\(n, e) -> (rmType n, Thunk newenv (rmType e))
newenv = Env $ Map.union (Map.fromList thunks) syms
eval1 newenv (rmType expr)
Lam name expr -> Right $ Clos env (rmType name) (rmType expr)
Call f arg -> do
vf <- eval1 env (rmType f)
varg <- eval1 env (rmType arg)
call vf varg
IfMatch inE pat thenE elseE -> do
inV <- eval1 env (rmType inE)
case patternMatch (rmType pat) inV of
Nothing -> eval1 env (rmType elseE)
Just bindings -> eval1 (Env $ Map.union (Map.fromList bindings) syms) (rmType thenE)
where
elimThunk :: Val -> Either Text Val
elimThunk (Thunk newenv e) = elimThunk =<< eval1 newenv e
elimThunk x = Right x
-- | If `val` matches `pat`, return Just a list of bound variables.
patternMatch :: Pattern -> Val -> Maybe [(Name, Val)]
patternMatch pat val = case pat of
PatLiteral l -> case val of
Literal l' | l == l' -> Just []
_ -> Nothing
PatVal n -> Just [(n, val)]
PatConstr conName pats -> case val of
Tag tName vals
| tName == conName && length vals == length pats
-> fmap concat $ sequence $ zipWith (patternMatch . rmType) pats vals
_ -> Nothing
call :: Val -> Val -> Either Text Val
call (Builtin (Builtin' _ b)) a = b a
call (Clos (Env syms) param body) a = do
let syms2 = Map.insert param a syms
eval1 (Env syms2) body
call val _ = error $ "attempted to call non-closure " ++ show val