-
Notifications
You must be signed in to change notification settings - Fork 0
/
Infer.hs
373 lines (320 loc) · 10.7 KB
/
Infer.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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
{- Part of the source code in this file was adopted from M.P. Jones,
- "Typing Haskell in Haskell" -}
module Infer (
Assump(..),
elookup,getType,
Instantiable(..),
TI(..), initTI, InferRet(..), Infer(..),
tiLit, tiExpr, split, tiDeclT, tiProgT,
initAS
) where
import Pretty
import Util
import Idx
import Types
import Classes
import ExprU
import Run
import Debug.Trace
----Type Inference Monad----
data Assump = AMap Idx Scheme
deriving (Show)
instance Types Assump where
apply s (AMap i tsc) = AMap i (apply s tsc)
tv (AMap i tsc) = tv tsc
instance Pretty Assump where
pretty (AMap i tsc) = pretty i <> text ":" <+> pretty tsc
elookup :: Monad m => Idx -> [Assump] -> m Scheme
elookup (IdS is) [] = fail ("unbound id: "++(is))
elookup i ((AMap curi tsc):as)
| i==curi = return tsc
| otherwise = elookup i as
getType :: [Assump] -> Idx -> TI (Qual Type)
getType as i = do
tsch <- elookup i as
freshInst tsch
type TI a = State (Subst,Int) a
initTI :: (Subst,Int)
initTI = ([],0)
getSubst :: TI Subst
getSubst = do
(s,_) <- get
return s
incCounter :: TI Int
incCounter = do
(s,i) <- get
put (s,i+1)
return i
extSubst :: Subst -> TI ()
extSubst news = modify (\(s,i)->(scomp news s,i))
newTVar :: Kind -> TI Type
newTVar k = do
i <- incCounter
return $ TyVar (TVar (IdS ("__v"++(show i))) k)
freshInst :: Scheme -> TI (Qual Type)
freshInst s@(Forall ks qt) = do
ts <- mapM newTVar ks
return ((inst ts qt))
unify :: Type -> Type -> TI ()
unify t1 t2 = do
s <- getSubst
s2 <- mgu (apply s t1) (apply s t2)
extSubst s2
-- substitube out TyQuant variables
class Instantiable t where
inst :: [Type] -> t -> t
instance Instantiable Type where
inst ts (TyApp l r) = TyApp (inst ts l) (inst ts r)
inst ts (TyQuant i) = ts!!i
inst ts t = t
instance Instantiable a => Instantiable [a] where
inst ts = map (inst ts)
instance Instantiable t => Instantiable (Qual t) where
inst ts (ps :=> t) = inst ts ps :=> inst ts t
instance Instantiable Pred where
inst ts (Pred c t) = Pred c (inst ts t)
data InferRet t = InferRet {irpreds :: [Pred], irt :: t}
type Infer e t = ClassEnv -> [Assump] -> e -> TI (InferRet t)
tiLit :: Lit -> InferRet Type
tiLit (LiNum i) = InferRet {irpreds=[], irt=tInt}
tiLit (LiUnit) = InferRet {irpreds=[], irt=tUnit}
retType :: Type -> InferRet Type
retType t = InferRet {irpreds=[], irt=t}
intop :: Type -> Type -> TI Type
intop t1 t2 = do
unify t1 tInt
unify t2 tInt
return tInt
intpred :: Type -> Type -> TI Type
intpred t1 t2 = do
unify t1 tInt
unify t2 tInt
return tBool
boolop :: Type -> Type -> TI Type
boolop t1 t2 = do
unify t1 tBool
unify t2 tBool
return tBool
tiPrim2 :: PrimOp2 -> Type -> Type -> TI Type
tiPrim2 PrPair t1 t2 = return $ mkPair t1 t2
tiPrim2 PrPlus t1 t2 = intop t1 t2
tiPrim2 PrMinus t1 t2 = intop t1 t2
tiPrim2 PrGt t1 t2 = intpred t1 t2
tiPrim2 PrLt t1 t2 = intpred t1 t2
tiPrim2 PrEqq t1 t2 = intpred t1 t2
tiPrim2 PrAnd t1 t2 = boolop t1 t2
tiPrim2 PrOr t1 t2 = boolop t1 t2
tiPrim1 :: PrimOp1 -> Type -> TI (InferRet Type)
tiPrim1 PrInl t = do
newtv <- newTVar Star
return $ retType (mkSum t newtv)
tiPrim1 PrInr t = do
newtv <- newTVar Star
return $ retType (mkSum newtv t)
tiPrim1 PrFst t = do
t1 <- newTVar Star
t2 <- newTVar Star
unify t (mkChoice t1 t2)
return $ retType t1
tiPrim1 PrSnd t = do
t1 <- newTVar Star
t2 <- newTVar Star
unify t (mkChoice t1 t2)
return $ retType t2
tiPrim1 PrFix t = do
t1 <- newTVar Star
unify t (mkArrow tUU t1 t1)
return $ retType t1
tiPrim1 PrSNew t = do
return $ retType (mkRef tS t)
tiPrim1 PrWNew t = do
return $ retType (mkRef tW t)
tiPrim1 PrRelease t = do
rq <- newTVar Star
t1 <- newTVar Star
unify t (mkRef rq t1)
return $ retType (mkSum t1 tUnit)
tiPrim1 PrSRelease t = do
t1 <- newTVar Star
unify t (mkRef tS t1)
return $ retType t1
tiPrim1 PrSwap t = do
t1 <- newTVar Star
rq <- newTVar Star
unify t (mkPair (mkRef rq t1) t1)
return $ retType t
tiPrim1 PrSSwap t = do
t1 <- newTVar Star
t2 <- newTVar Star
unify t (mkPair (mkRef tS t1) t2)
return $ retType $ mkPair (mkRef tS t2) t1
tiExpr :: Infer Expr Type
tiExpr ce as (ExLit l) = return $ tiLit l
tiExpr ce as (ExVar i) = do
sc <- elookup i as
(ps :=> t) <- freshInst sc
return $ InferRet {irpreds=ps,irt=t}
tiExpr ce as (ExGVar i) = do
sc <- elookup i as
(ps :=> t) <- freshInst sc
return $ InferRet {irpreds=ps,irt=t}
tiExpr ce as elam@(ExAbs aq i e) = do
newtv <- newTVar Star
let newas = AMap i (toScheme newtv)
InferRet {irpreds=retp, irt=rett} <- tiExpr ce (newas:as) e
-- Create Closure Type
let envfvs = fv elam
envqts <- mapM (getType as) envfvs
let (envpreds, envts) = sepQuals envqts
let funpreds = case aq of
AQU -> (map mkDup envts)++(map mkDrop envts)
AQR -> map mkDup envts
AQA -> map mkDrop envts
AQL -> []
return $ InferRet {irpreds=envpreds++retp++funpreds,
irt=mkArrow (atqual aq) newtv rett}
where
atqual AQU = tUU
atqual AQR = tRU
atqual AQA = tAU
atqual AQL = tLU
tiExpr ce as (ExApp e1 e2) = do
InferRet {irpreds=e1p, irt=e1t} <- tiExpr ce as e1
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce as e2
rettv <- newTVar Star
envtv <- newTVar Star
unify (mkArrow envtv e2t rettv) e1t
return $ InferRet {irpreds=e1p++e2p, irt=rettv}
tiExpr ce as (ExLet i e1 e2) = do
InferRet {irpreds=e1p, irt=e1as} <- tiDecl ce as (DcLet i e1)
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce (e1as:as) e2
return $ InferRet {irpreds=e1p++e2p, irt=e2t}
tiExpr ce as (ExLetp i1 i2 e1 e2) = do
InferRet {irpreds=e1p, irt=e1t} <- tiExpr ce as e1
newtv1 <- newTVar Star
newtv2 <- newTVar Star
let pairt = mkPair newtv1 newtv2
unify pairt e1t
let newas = [AMap i1 (toScheme newtv1), AMap i2 (toScheme newtv2)]
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce (newas++as) e2
return $ InferRet {irpreds = e1p++e2p, irt=e2t}
tiExpr ce as (ExMatch e i1 e1 i2 e2) = do
InferRet {irpreds=ep, irt=et} <- tiExpr ce as e
newtv1 <- newTVar Star
newtv2 <- newTVar Star
let sumt = mkSum newtv1 newtv2
unify sumt et
let i1as = AMap i1 (toScheme newtv1)
let i2as = AMap i2 (toScheme newtv2)
InferRet {irpreds=e1p, irt=e1t} <- tiExpr ce (i1as:as) e1
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce (i2as:as) e2
unify e1t e2t
return $ InferRet {irpreds = ep++e1p++e2p, irt=e1t}
tiExpr ce as (ExWith e1 e2) = do
InferRet {irpreds=e1p, irt=e1t} <- tiExpr ce as e1
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce as e2
return $ InferRet {irpreds=e1p++e2p, irt=mkChoice e1t e2t}
-- First instantiate schemes, then apply dup constraint to type instances
-- but rebind to original schemes, since we don't want to lose polymorphism thorugh
-- a dup, e.g. a dup acts as a let-generalizable location
tiExpr ce as (ExDup dupes newvs e) = do
let dupvs = map (\(ExVar i) -> i) dupes
dupvtschs <- mapM (\i -> elookup i as) dupvs
dupvqts <- mapM freshInst dupvtschs
let (dupvPrds, dupvTyps) = sepQuals dupvqts
let duppreds = map mkDup dupvTyps
let newvtpairs = zip newvs dupvtschs
let newas = concat $ map (\((i1,i2),t) -> [AMap i1 t, AMap i2 t]) newvtpairs
InferRet {irpreds=ep, irt=et} <- tiExpr ce (newas++as) e
return $ InferRet {irpreds=(dupvPrds++duppreds++ep), irt=et}
tiExpr ce as (ExDrop dropes e) = do
let dropvs = map (\(ExVar i ) -> i) dropes
dropvtschs <- mapM (\i -> elookup i as) dropvs
dropvqts <- mapM freshInst dropvtschs
let (dropvPrds, dropvTyps) = sepQuals dropvqts
let droppreds = map mkDrop dropvTyps
InferRet {irpreds=ep, irt=et} <- tiExpr ce as e
return $ InferRet {irpreds=(dropvPrds++droppreds++ep), irt=et}
tiExpr ce as (ExPrim1 pOp e) = do
InferRet {irpreds=ep, irt=et} <- tiExpr ce as e
InferRet{irpreds=opp, irt=opt} <- tiPrim1 pOp et
return $ InferRet {irpreds=ep++opp, irt=opt}
tiExpr ce as (ExPrim2 pOp e1 e2) = do
InferRet {irpreds=e1p, irt=e1t} <- tiExpr ce as e1
InferRet {irpreds=e2p, irt=e2t} <- tiExpr ce as e2
rett <- tiPrim2 pOp e1t e2t
return $ InferRet {irpreds=e1p++e2p, irt=rett}
tiExprQT ce as e = do
InferRet {irpreds=p,irt=t} <- tiExpr ce as e
return (p,t)
---- Type Generalization ----
split :: Monad m => ClassEnv -> [TypeVar] -> [TypeVar] -> [Pred]
-> m ([Pred],[Pred])
split ce fixvs quantvs ps = do
ps' <- reduce ce ps
return $ partition testfixedpred ps'
where
-- Only include predicates that might be of use, e.g. ones
-- which have nonfixed variables
testfixedpred p = all (`elem` fixvs) (tv p)
---- Declaration Inference, used at let binding sites ----
tiDecl :: Infer Decl Assump
tiDecl ce as (DcLet i e)
-- Note Value restriction on generalization
| isGeneralizable e = do
eir <- tiExpr ce as e
s <- getSubst
let epreds = apply s (irpreds eir)
ety = apply s (irt eir)
fvs = tv (apply s as)
quantvs = tv ety \\ fvs
(dpreds,rpreds) <- {-trace (show "----\ni:"++"ty:"++(show $ pretty ety)++"env:"++(show as)) -}
split ce fvs quantvs epreds
let tsc = quantify quantvs (rpreds :=> ety)
return $ InferRet {irpreds=dpreds,irt=AMap i tsc}
| otherwise = do
InferRet {irpreds=retp,irt=rett} <- tiExpr ce as e
return $ InferRet {irpreds=retp,irt=AMap i (toScheme rett)}
tiDeclT :: ClassEnv -> [Assump] -> Idx -> Expr -> Assump
tiDeclT ce as i e =
let (inferret, (subst,counter)) = runState (tiDecl ce as (DcLet i e)) initTI in
let epreds = apply subst (irpreds inferret)
eas = apply subst (irt inferret)
in
case epreds of
[] -> eas
_ -> eas
---- Program Inference ----
tiProgT :: ClassEnv -> [Assump] -> [Decl] -> [Assump]
tiProgT ce as decls =
foldl addDecl [] decls
where
addDecl newAs (DcLet i e) = (tiDeclT ce (newAs++as) i e) : newAs
---- Initial Assumption Environment ----
mkQList i = mkList (TyQuant i)
initAS :: [Assump]
initAS = [
AMap (IdS "@l_nil")
(Forall [Star] ([] :=> mkQList 0)),
AMap (IdS "@l_unfold")
(Forall [Star] ([] :=> mkArrow tUU (mkQList 0) (mkSum
(mkPair (TyQuant 0) (mkQList 0))
tUnit)
)),
AMap (IdS "@l_cons")
(Forall [Star] ([] :=> mkArrow tUU (mkPair (TyQuant 0) (mkQList 0)) (mkQList 0)
)),
AMap (IdS "@lunit")
(toScheme tLU),
AMap (IdS "@ldispose")
(toScheme (mkArrow tUU tLU tUnit)),
AMap (IdS "@wrmap")
(Forall [Star, Star]
([] :=> mkArrow tUU
(mkArrow tUU (TyQuant 0) (TyQuant 0))
(mkArrow tUU
(mkRef (TyQuant 1) (TyQuant 0))
(mkRef (TyQuant 1) (TyQuant 0))
)
))
]