-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path12-untypes-lambdas.hs
118 lines (94 loc) · 2.94 KB
/
12-untypes-lambdas.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
{-# 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 -> 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
VFun :: (Value -> Either InterpError Value) -> Value
type Env = M.Map String Value
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 (VFun _) = "<function>"
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)
<* reservedOp "->"
<*> parseExpr
parseExpr :: Parser Expr
parseExpr = buildExpressionParser table parseAtom
where
table = [ [ Infix (Apply <$ reservedOp "") AssocLeft
]
, [ Infix (Add <$ reservedOp "+") AssocLeft
]
]
expr :: Parser Expr
expr = whiteSpace *> parseExpr <* eof
p :: String -> Expr
p s = case parse expr s of
Left err -> error (show err)
Right e -> e
interp :: Env -> Expr -> Either InterpError Value
interp env (Lit i) = do return $ VInt i
interp env (Var name) = case M.lookup name env of
Just val -> Right val
Nothing -> Left $ UndefinedVar name
interp env (Add e1 e2) = do
v1 <- interp env e1
v2 <- interp env e2
add v1 v2
where
add (VInt x) (VInt y) = Right $ VInt (x+y)
add (VFun _) _ = Left $ TypeMismatch e1
add _ (VFun _) = Left $ TypeMismatch e2
interp env e@(Lambda par e1) = case par of
Var name -> Right $ VFun (\exp -> interp (M.insert name exp env) e1)
otherwise -> Left $ ExpectedIdent e
interp env (Apply f e1) = do
f' <- interp env f >>= typeCheck
interp env e1 >>= f'
where
typeCheck (VFun f) = Right f
typeCheck (VInt _) = Left $ TypeMismatch f
eval :: String -> IO ()
eval s = case parse expr s of
Left err -> print err
Right e -> case interp M.empty e of
Left err -> putStrLn (showInterpError err)
Right v -> putStrLn (showValue v)