-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstlbool.hs
150 lines (117 loc) · 4 KB
/
stlbool.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
-- Type Checker for the Simply-Typed Lambda Calculus
-- Supported Language Features:
-- Abstractions
-- Application
-- Variables
-- Conditionals
-- Boolean Values
-- Supported Typing Features:
-- Arrow Types (Function Types)
-- Type Variables
-- Bool Type
module STLambdaBool
( Term (..)
, Type (..)
, Error (..)
, VContext (..)
, showTerm
, showType
, addBinding
, pushBinding
, shiftBindings
, typeof
)
where
data Term = Abs String Type Term
| App Term Term
| Var Int
| If Term Term Term
| Tru
| Fls
data Type = Arrow Type Type
| TVar String
| Bool
deriving Eq
data Error = ParamMismatch Type Type
| MissingArrow Type
| UnboundVar VContext Int
| NonBoolGaurd Type
| CondBranchMismatch Type Type
type Function a b = a -> Maybe b
instance Show Term where
show = showTerm (\a -> Nothing)
instance Show Type where
show = showType
instance Show Error where
show = showError
-- Contexts
type VContext = Function Int (String, Type)
addBinding :: Eq a => Function a b -> a -> b -> Function a b
addBinding f a b = \x -> if x == a then Just b else f x
pushBinding :: VContext -> (String, Type) -> VContext
pushBinding ctx p = addBinding (shiftBindings ctx) 0 p
shiftBindings :: VContext -> VContext
shiftBindings ctx = \x -> ctx (x - 1)
-- Show Functions
showTerm :: VContext -> Term -> String
showTerm _ Tru = "True"
showTerm _ Fls = "False"
showTerm ctx (If t1 t2 t3) = "if " ++ showTerm ctx t1 ++ " then " ++ showTerm ctx t2 ++ " else " ++ showTerm ctx t3
showTerm ctx (Abs s ty tm) =
"\\" ++ s ++ " : " ++ show ty ++ ". " ++ showTerm ctx' tm
where ctx' = pushBinding ctx (s, ty)
showTerm ctx (App t1 t2) =
"(" ++ showTerm ctx t1 ++ ") (" ++ showTerm ctx t2 ++ ")"
showTerm ctx (Var v) =
case ctx v of
Nothing -> "(Var " ++ show v ++ ")"
Just (s, _) -> s
showType :: Type -> String
showType Bool = "Bool"
showType (Arrow a b) =
case a of
Arrow _ _ -> wparen
_ -> showType a ++ " -> " ++ showType b
where wparen = "(" ++ showType a ++ ") -> " ++ showType b
showType (TVar s) = s
showError :: Error -> String
showError (ParamMismatch t1 t2) = "Parameter type mismatch. Expected type (" ++ show t1 ++ "), supplied type (" ++ show t2 ++ ")"
showError (MissingArrow t) = "Expected arrow type, supplied type (" ++ show t ++ ")"
showError (UnboundVar ctx i) = "Variable indexed by \'" ++ show i ++ "\' not in the present context"
showError (NonBoolGaurd t) = "Expected type Bool to guard, supplied type (" ++ show t ++ ")"
showError (CondBranchMismatch t1 t2) = "Type mismatch in conditional branchs. (" ++ show t1 ++ ") is not equivalent to (" ++ show t2 ++ ")"
-- toFunct
toFunct :: Eq a => [(a, b)] -> Function a b
toFunct [] = \a -> Nothing
toFunct (x:xs) = \n -> if n == a then Just b else (toFunct xs) n where (a, b) = x
-- Typing
typeof :: Term -> Either Error Type
typeof = typeof0 (toFunct [])
typeof0 :: VContext -> Term -> Either Error Type
typeof0 _ Tru = return Bool
typeof0 _ Fls = return Bool
typeof0 ctx (Abs s ty1 tm) = (Arrow ty1) <$> typeof0 ctx' tm
where ctx' = pushBinding ctx (s, ty1)
typeof0 ctx (App t1 t2) = do
ty1 <- typeof0 ctx t1
ty2 <- typeof0 ctx t2
case ty1 of
Arrow ty11 ty12 ->
if ty11 == ty2
then Right ty12
else Left $ ParamMismatch ty11 ty2
_ -> Left $ MissingArrow ty1
typeof0 ctx (Var v) =
case ctx v of
Nothing -> Left $ UnboundVar ctx v
Just (_, t) -> Right t
typeof0 ctx (If t1 t2 t3) = do
ty1 <- typeof0 ctx t1
ty2 <- typeof0 ctx t2
ty3 <- typeof0 ctx t3
if ty1 == Bool
then
if ty2 == ty3
then Right ty2
else Left $ CondBranchMismatch ty2 ty3
else Left $ NonBoolGaurd ty1