-
Notifications
You must be signed in to change notification settings - Fork 0
/
Fun.hs
78 lines (61 loc) · 2.5 KB
/
Fun.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
module Fun where
data Expr = Lit Bool
| Var String
| Let String Expr Expr
| If Expr Expr Expr
| Lambda String Expr
| App Expr Expr
deriving (Eq)
instance Show Expr where
show (Lit b) = show b
show (Var v) = v
show (Let v e1 e2) = "let " ++ v ++ " = " ++ show e1 ++ " in " ++ show e2
show (If eb e1 e2) = "if " ++ show eb ++
" then " ++ show e1 ++
" else " ++ show e2
show (Lambda v e) = "(\\" ++ v ++ " -> " ++ show e ++ ")"
show (App e1 e2) = show e1 ++ " " ++ show e2
data Value = Boolean Bool
| Function String Expr
deriving (Eq)
instance Show Value where
show (Boolean b) = show b
show (Function s e) = "(\\" ++ s ++ " -> " ++ show e ++ ")"
type State = String -> Value
empty :: State
empty = const (Boolean False)
extend :: State -> String -> Value -> State
extend st name val = \x -> if x == name then val else st x
subst :: String -> Expr -> Expr -> Expr
subst v e (Lit b) = Lit b
subst v e (Var v') | v == v' = e
| otherwise = Var v'
subst v e (Let v' e1 e2) | v == v' = Let v' (subst v e e1) e2
| otherwise = Let v' (subst v e e1) (subst v e e2)
subst v e (If e1 e2 e3) = If (subst v e e1)
(subst v e e2)
(subst v e e3)
subst v e (Lambda v' e1) | v == v' = Lambda v' e1
| otherwise = Lambda v' (subst v e e1)
subst v e (App e1 e2) = App (subst v e e1) (subst v e e2)
evalE :: State -> Expr -> Value
evalE st (Lit b) = Boolean b
evalE st (Var v) = st v
evalE st (Let v e1 e2) = evalE st (subst v e1 e2)
evalE st (If e1 e2 e3) = case evalE st e1 of
Function _ _ -> error "not a boolean"
Boolean True -> evalE st e2
Boolean False -> evalE st e3
evalE st (Lambda v e) = Function v e
evalE st (App e1 e2) = case evalE st e1 of
Boolean _ -> error "can't apply a boolean"
Function v e -> evalE st (subst v e2 e)
lognot :: Expr
lognot = Lambda "x" $ If (Var "x") (Lit False) (Lit True)
logor :: Expr
logor = Lambda "x" $ Lambda "y" $ If (Var "x") (Lit True) (Var "y")
logand :: Expr
logand = Lambda "x" $ Lambda "y" $ If (Var "x") (Var "y") (Lit False)
logxor :: Expr
logxor = Let "not" lognot $ Lambda "x" $ Lambda "y" $
If (Var "x") (Var "not" `App` Var "y") (Var "y")