on master help sign in
Add basics of type-checking and inference. Uses constraint generation method.
commitf5bdeae81549a7626318989bbd886a092573c55b authorevancz <info@elm-lang.org> dateFri 11 May 2012, 06:28 (14 years ago) parent3a83d69
4 files changed+136−10
src/Parse/ParseTypes.hs+1−1 src/Types/Constrain.hs+89 src/Types/Types.hs+9−9 src/Types/Unify.hs+37
src/Parse/ParseTypes.hs+1−1
@@ -15,7 +15,7 @@ typeVar = do whitespace; t <- item
1515 ID "Char" -> return CharT
1616 ID "Bool" -> return BoolT
1717 ID (v:vs) -> return (if isUpper v then ADT (v:vs) []
18− else VarT (v:vs))
18+ else VarT 0) --(v:vs))
1919 _ -> zero
2020
2121typeList = do t LBRACKET; ti <- typeExpr; t RBRACKET; return $ ADT "List" []
src/Types/Constrain.hsnew file+89
@@ -0,0 +1,89 @@
1+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
2+module Constrain where
3+
4+import Ast
5+import Types
6+import qualified Data.Set as Set
7+import qualified Data.Map as Map
8+import Control.Monad (liftM,mapM)
9+import Control.Monad.State (evalState, State, get, put)
10+
11+data Constraint = Type :=: Type
12+ | Type :<: Type
13+ | Type :<<: Scheme
14+ deriving (Eq, Ord, Show)
15+
16+-- Wrapper around State monad.
17+newtype GuidCounter a = GC { runGC :: State Int a }
18+ deriving (Monad)
19+
20+-- Get the next GUID, incrementing the counter.
21+guid :: GuidCounter Int
22+guid = GC $ do n <- get
23+ put (n + 1)
24+ return n
25+
26+beta = VarT `liftM` guid
27+unionA = Map.unionWith (++)
28+unionsA = Map.unionsWith (++)
29+
30+constrain expr = Set.toList cs
31+ where (as,cs,t) = evalState (runGC $ inference expr) 0
32+
33+inference (Var x) =
34+ do b <- beta
35+ return (Map.singleton x [b], Set.empty, b)
36+inference (App e1 e2) =
37+ do (a1,c1,t1) <- inference e1
38+ (a2,c2,t2) <- inference e2
39+ b <- beta
40+ return ( unionA a1 a2
41+ , Set.unions [c1,c2,Set.singleton $ t1 :=: (LambdaT t2 b)]
42+ , b )
43+inference (Lambda x e) =
44+ do (a,c,t) <- inference e
45+ b <- beta
46+ return ( Map.delete x a
47+ , Set.union c . Set.fromList . map (:=: b) $
48+ Map.findWithDefault [] x a
49+ , LambdaT b t )
50+inference (Let defs e) =
51+ do (a,c,t) <- inference e
52+ let (xs,es) = unzip defs
53+ (as,cs,ts) <- unzip3 `liftM` mapM inference es
54+ let assumptions = unionsA (a:as)
55+ let f x t = map (:<: t) $ Map.findWithDefault [] x assumptions
56+ let constraints = Set.fromList . concat $ zipWith f xs ts
57+ return ( foldr Map.delete assumptions xs
58+ , Set.unions $ c:constraints:cs
59+ , t )
60+
61+inference (If e1 e2 e3) =
62+ do (a1,c1,t1) <- inference e1
63+ (a2,c2,t2) <- inference e2
64+ (a3,c3,t3) <- inference e3
65+ return ( unionsA [a1,a2,a3]
66+ , Set.unions [c1,c2,c3, Set.fromList [ t1 :=: BoolT, t2 :=: t3 ] ]
67+ , t2 )
68+
69+inference (Data name es) =
70+ do (as,cs,ts) <- unzip3 `liftM` mapM inference es
71+ return ( unionsA as, Set.unions cs, ADT name ts )
72+
73+inference other =
74+ case other of
75+ Number _ -> primitive IntT
76+ Chr _ -> primitive CharT
77+ Boolean _ -> primitive BoolT
78+ _ -> beta >>= primitive
79+
80+primitive t = return (Map.empty, Set.empty, t)
81+{--
82+ Let x e1 e2 ->
83+ do (a1,c1,t1) <- inference e1
84+ (a2,c2,t2) <- inference e2
85+ let ts = Map.findWithDefault (error "inference") x a
86+ return ( unionA a1 $ Map.delete x a2
87+ , Set.unions [ c1, c2, Set.fromList $ map (:<: t1) ts ]
88+ , t2 )
89+--}
src/Types/Types.hs+9−9
@@ -2,19 +2,21 @@
22module Types where
33
44import Data.List (intercalate)
5−import Data.IORef
6−import System.IO.Unsafe
5+import qualified Data.Set as Set
6+
7+type X = Int
78
89data Type = IntT
910 | StringT
1011 | CharT
1112 | BoolT
1213 | LambdaT Type Type
13− | VarT String
14− | ForallT String Type
14+ | VarT X
1515 | AppT String [Type]
1616 | ADT String [Type]
17− deriving (Eq)
17+ deriving (Eq, Ord)
18+
19+data Scheme = Forall (Set.Set X) Type deriving (Eq, Ord, Show)
1820
1921data Constructor = Constructor String [Type] deriving (Eq, Show)
2022
@@ -26,9 +28,7 @@ instance Show Type where
2628 ; CharT -> "Char"
2729 ; BoolT -> "Bool"
2830 ; LambdaT t1 t2 -> show t1 ++ " -> " ++ show t2
29− ; VarT x -> x
30− ; ForallT x t' -> "forall " ++ x ++ ". " ++ show t'
31+ ; VarT x -> show x
3132 ; AppT name args -> name ++ " " ++ unwords (map show args)
32− ; ADT name constrs ->
33− name ++ " = " ++ intercalate " | " (map show constrs)
33+ ; ADT name constrs -> name
3434 }
src/Types/Unify.hsnew file+37
@@ -0,0 +1,37 @@
1+
2+module Unify where
3+
4+import Constrain
5+import Control.Arrow (second)
6+import Types
7+
8+unify expr = ( constrain expr, solver (constrain expr) [] )
9+
10+solver [] subs = Right subs
11+
12+solver ((t1 :<: t2) : cs) subs = solver ((t1 :=: t2) : cs) subs
13+
14+solver ((ADT n1 ts1 :=: ADT n2 ts2) : cs) subs =
15+ if n1 /= n2 then Left "unification error" else
16+ solver (zipWith (:=:) ts1 ts2 ++ cs) subs
17+
18+solver ((LambdaT t1 t2 :=: LambdaT t1' t2') : cs) subs =
19+ solver ([ t1 :=: t1', t2 :=: t2' ] ++ cs) subs
20+
21+solver ((VarT x :=: t) : cs) subs =
22+ solver (map (cSub x t) cs) . map (second $ tSub x t) $ (x,t):subs
23+
24+solver ((t :=: VarT x) : cs) subs =
25+ solver (map (cSub x t) cs) . map (second $ tSub x t) $ (x,t):subs
26+
27+solver ((t1 :=: t2) : cs) subs =
28+ if t1 /= t2 then Left $ show t1 ++ " is not equal to " ++ show t2 else
29+ solver cs subs
30+
31+
32+cSub k v (t1 :=: t2) = tSub k v t1 :=: tSub k v t2
33+cSub k v (t1 :<: t2) = tSub k v t1 :=: tSub k v t2
34+
35+tSub k v (VarT x) = if k == x then v else (VarT x)
36+tSub k v (LambdaT t1 t2) = LambdaT (tSub k v t1) (tSub k v t2)
37+tSub _ _ t = t