-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path13-closures-and-types.hs
132 lines (106 loc) · 3.44 KB
/
13-closures-and-types.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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
{-# LANGUAGE GADTs #-}
import Prelude
import Parsing2
import qualified Data.Map as M
data Expr where
Var :: String -> Expr
Lit :: Integer -> Expr
Add :: Expr -> Expr -> Expr
Lambda :: Expr -> Maybe Type -> Expr -> Expr
Apply :: Expr -> Expr -> Expr
deriving (Show)
-- (^x -> x + 1) 2
data InterpError where
UndefinedVar :: String -> InterpError
TypeMismatch :: Expr -> InterpError
ExpectedIdent :: Expr -> InterpError
deriving (Show)
data Value where
VInt :: Integer -> Value
VClosure :: String -> Expr -> Env -> Value
type Env = M.Map String Value
data Type where
TyInt :: Type
TyFun :: Type -> Type -> Type
deriving (Show)
showInterpError :: InterpError -> String
showInterpError (UndefinedVar name) = "Undefined variable " ++ name
showInterpError (TypeMismatch _) = "Unexpected type" -- FIXME
showInterpError (ExpectedIdent _) = "Lambda parameter must be an identifier"
showValue :: Value -> String
showValue (VInt i) = show i
showValue (VClosure name expr env) = "function " ++ name ++ ": " ++ show expr
lexer :: TokenParser u
lexer = makeTokenParser emptyDef
parens :: Parser a -> Parser a
parens = getParens lexer
identifier :: Parser String
identifier = getIdentifier lexer
reservedOp :: String -> Parser ()
reservedOp = getReservedOp lexer
whiteSpace :: Parser ()
whiteSpace = getWhiteSpace lexer
integer :: Parser Integer
integer = getInteger lexer
parseAtom :: Parser Expr
parseAtom
= Var <$> identifier
<|> Lit <$> integer
<|> parseLambda
<|> parens parseExpr
parseLambda :: Parser Expr
parseLambda =
Lambda <$ reservedOp "^"
<*> (Var <$> identifier)
<*> optionMaybe (reservedOp "[" *> parseType <* reservedOp "]")
<* reservedOp "->"
<*> parseExpr
parseExpr :: Parser Expr
parseExpr = buildExpressionParser table parseAtom
where
table = [ [ Infix (Apply <$ reservedOp "") AssocLeft
]
, [ Infix (Add <$ reservedOp "+") AssocLeft
]
]
parseTypeAtom :: Parser Type
parseTypeAtom
= TyInt <$ reservedOp "Int"
<|> parens parseType
parseType :: Parser Type
parseType = buildExpressionParser table parseTypeAtom
where
table = [ [ Infix (TyFun <$ reservedOp "->") AssocRight
]
]
expr :: Parser Expr
expr = whiteSpace *> parseExpr <* eof
interpC :: Env -> Expr -> Either InterpError Value
interpC env (Lit i) = do return $ VInt i
interpC env (Var name) = case M.lookup name env of
Just val -> Right val
Nothing -> Left $ UndefinedVar name
interpC env (Add e1 e2) = do
v1 <- interpC env e1
v2 <- interpC env e2
add v1 v2
where
add (VInt x) (VInt y) = Right $ VInt (x+y)
add (VClosure _ _ _) _ = Left $ TypeMismatch e1
add _ (VClosure _ _ _) = Left $ TypeMismatch e2
interpC env e@(Lambda par t e1) = case par of
Var name -> Right $ VClosure name e1 env
otherwise -> Left $ ExpectedIdent e
interpC env (Apply f e1) = do
f' <- interpC env f >>= typeCheck
interpC env e1 >>= f'
where
typeCheck (VClosure name expr env1) =
Right (\par -> interpC (M.insert name par env1) expr)
typeCheck (VInt _) = Left $ TypeMismatch f
eval :: String -> IO ()
eval s = case parse expr s of
Left err -> print err
Right e -> case interpC M.empty e of
Left err -> putStrLn (showInterpError err)
Right v -> putStrLn (showValue v)