-
Notifications
You must be signed in to change notification settings - Fork 0
/
stllet.hs
134 lines (101 loc) · 3.44 KB
/
stllet.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
-- Type Checker for the Simply-Typed Lambda Calculus
-- Supported Language Features:
-- Abstractions
-- Application
-- Variables
-- Supported Typing Features:
-- Arrow Types (Function Types)
-- Type Variables
module STLambda
( Term (..)
, Type (..)
, Error (..)
, VContext (..)
, showTerm
, showType
, addBinding
, pushBinding
, shiftBindings
, typeof
)
where
data Term = Abs String Type Term
| App Term Term
| Var Int
| Let String Term Term
data Type = Arrow Type Type
| TName String
deriving Eq
data Error = ParamMismatch Type Type
| MissingArrow Term
| UnboundVar VContext Int
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 ctx (Let s t1 t2) =
"let " ++ s ++ " = " ++ showTerm ctx t1 ++ " in " ++ showTerm ctx' t2
where ty = let ty1 = typeof t1
in case ty1 of
Left _ -> error "type cannot be evaluated for binding"
Right ty1' -> ty1'
ctx' = pushBinding ctx (s, ty)
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 (Arrow a b) =
case a of
Arrow _ _ -> wparen
_ -> showType a ++ " -> " ++ showType b
where wparen = "(" ++ showType a ++ ") -> " ++ showType b
showType (TName s) = s
showError :: Error -> String
showError (ParamMismatch t1 t2) = "expected type (" ++ show t1 ++ "), supplied type (" ++ show t2 ++ ")"
showError (MissingArrow t) = "expected arrow type in the term \'" ++ show t ++ "\'"
showError (UnboundVar ctx i) = "variable indexed by \'" ++ show i ++ "\' not in the present context"
-- 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 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 (App t1 t2)
typeof0 ctx (Var v) =
case ctx v of
Nothing -> Left $ UnboundVar ctx v
Just (_, t) -> Right t
typeof0 ctx (Let s t1 t2) = do
ty1 <- typeof0 ctx t1
typeof0 (pushBinding ctx (s, ty1)) t2