1 implementation module infer
5 import qualified Data.Map as DM
6 from Data.Map import instance Functor (Map k)
7 import qualified Data.Set as DS
13 import Control.Applicative
15 import Control.Monad.Trans
16 import qualified Control.Monad.State as MS
17 import Control.Monad.RWST
21 :: TypeEnv :== 'DM'.Map String Scheme
22 :: Constraint :== (Type, Type)
23 :: Subst :== 'DM'.Map String Type
24 :: Unifier :== (Subst, [Constraint])
25 :: Infer a :== RWST TypeEnv [Constraint] InferState (Either TypeError) a
26 :: InferState = { count :: Int }
27 :: Solve a :== 'MS'.StateT Unifier (Either TypeError) a
28 :: TypeError = UnboundVariable String
31 nullSubst = 'DM'.newMap
33 uni :: Type Type -> Infer ()
34 uni t1 t2 = tell [(t1, t2)]
36 inEnv :: (String, Scheme) (Infer a) -> Infer a
37 inEnv (x, sc) m = local (\e->'DM'.put x sc $ 'DM'.del x e) m
40 letters = map toString $ [1..] >>= flip replicateM ['a'..'z']
43 fresh = get >>= \s=:{count}->put {s & count=count + 1} >>| pure (VarType $ letters !! count)
45 lookupEnv :: String -> Infer Type
46 lookupEnv x = asks ('DM'.get x)
47 >>= maybe (liftT $ Left $ UnboundVariable x) instantiate
52 ftv :: a -> 'DS'.Set String
54 instance Substitutable Type
56 apply s t=:(VarType a) = maybe t id $ 'DM'.get a s
57 apply s (Arrow t1 t2) = Arrow (apply s t1) (apply s t2)
60 ftv (VarType a) = 'DS'.singleton a
61 ftv (Arrow t1 t2) = 'DS'.union (ftv t1) (ftv t2)
64 instance Substitutable Scheme
66 apply s (Forall as t) = Forall as $ apply (foldr 'DM'.del s as) t
67 ftv (Forall as t) = 'DS'.difference (ftv t) ('DS'.fromList as)
69 instance Substitutable [a] | Substitutable a
71 apply s ls = map (apply s) ls
72 ftv t = foldr ('DS'.union o ftv) 'DS'.newSet t
74 instance Substitutable TypeEnv where
75 apply s env = fmap (apply s) env
76 ftv env = ftv $ 'DM'.elems env
78 instantiate :: Scheme -> Infer Type
79 instantiate (Forall as t) = mapM (const fresh) as
80 >>= \as`->let s = 'DM'.fromList $ zip2 as as` in pure $ apply s t
81 generalize :: TypeEnv Type -> Scheme
82 generalize env t = Forall ('DS'.toList $ 'DS'.difference (ftv t) (ftv env)) t
84 infer :: Expression -> Infer Type
85 infer (Literal v) = case v of
87 Bool _ = pure BoolType
88 Char _ = pure CharType
89 infer (Variable s) = lookupEnv s
94 >>= \tv->uni t1 (Arrow t2 tv)
98 >>= \tv->inEnv (s, Forall [] tv) (infer e)
99 >>= \t-> pure (Arrow tv t)
103 >>= \t1->inEnv (x, generalize en t1) (infer e2)
104 infer (Code c) = fresh >>= \v->pure case c of
105 "add" = Arrow v (Arrow v v)
106 "sub" = Arrow v (Arrow v v)
107 "mul" = Arrow v (Arrow v v)
108 "div" = Arrow v (Arrow v v)
109 "and" = Arrow v (Arrow v BoolType)
110 "or" = Arrow v (Arrow v BoolType)