on master help sign in
Refactor type environment

Migrate some functions to Environment.hs, add built-in types like _List and _Tuple2.

commita3a7b3ef622da1b22c049a614059c7fa1f280022 authorEvan Czaplicki <info@elm-lang.org> dateWed 17 Jul 2013, 19:29 (13 years ago) parent90c5c7d
5 files changed+140−94
compiler/Type/Constrain/Expression.hs+5−35 compiler/Type/Constrain/Literal.hs+1−1 compiler/Type/Constrain/Pattern.hs+8−34 compiler/Type/Environment.hs+114−22 compiler/Type/Inference.hs+12−2
compiler/Type/Constrain/Expression.hs+5−35
@@ -3,7 +3,6 @@ module Type.Constrain.Expression where
33import qualified Data.List as List
44import qualified Data.Map as Map
55import qualified Data.Set as Set
6−import Data.Map ((!))
76import Control.Arrow (second)
87import Control.Applicative ((<$>),(<*>))
98import qualified Control.Monad as Monad
@@ -33,7 +32,7 @@ test str =
3332 case iParse expr "" str of
3433 Left err -> error $ "Parse error at " ++ show err
3534 Right expression -> do
36− env <- Env.initialEnvironment
35+ env <- Env.initialEnvironment []
3736 var <- flexibleVar
3837 let expr = SD.sortDefs expression
3938 print (pretty expr)
@@ -50,7 +49,7 @@ test str =
5049
5150constrain :: Env.Environment -> LExpr a b -> Type -> IO TypeConstraint
5251constrain env (L _ _ expr) tipe =
53− let list t = TermN (App1 (Env.get env Env.builtin "[_]") t) in
52+ let list t = TermN (App1 (Env.get env Env.types "_List") t) in
5453 case expr of
5554 Literal lit -> return $ Literal.constrain env lit tipe
5655
@@ -91,7 +90,7 @@ constrain env (L _ _ expr) tipe =
9190
9291 MultiIf branches -> CAnd <$> mapM constrain' branches
9392 where
94− bool = Env.get env Env.builtin "Bool"
93+ bool = Env.get env Env.types "Bool"
9594 constrain' (b,e) = do
9695 cb <- constrain env b bool
9796 ce <- constrain env e tipe
@@ -165,7 +164,7 @@ constrain env (L _ _ expr) tipe =
165164 return ((name, v), c)
166165
167166 Markdown _ ->
168− return $ tipe === Env.get env Env.builtin "Element"
167+ return $ tipe === Env.get env Env.types "Element"
169168
170169 Let defs body ->
171170 do c <- constrain env body tipe
@@ -187,7 +186,7 @@ constrainDef env info (pattern, expr, maybeTipe) =
187186 do flexiVars <- mapM (\_ -> flexibleVar) qs
188187 let inserts = zipWith (\arg typ -> Map.insert arg (VarN typ)) qs flexiVars
189188 env' = env { Env.value = List.foldl' (\x f -> f x) (Env.value env) inserts }
190− typ <- instantiateType tipe
189+ typ <- Env.instantiateType env tipe
191190 let scheme = Scheme { rigidQuantifiers = [],
192191 flexibleQuantifiers = flexiVars,
193192 constraint = CTrue,
@@ -216,35 +215,6 @@ constrainDef env info (pattern, expr, maybeTipe) =
216215 , c1 )
217216
218217
219−instantiateType :: SrcT.Type -> IO Type
220−instantiateType sourceType = instantiateTypeWithContext sourceType Map.empty
221−
222−instantiateTypeWithContext :: SrcT.Type -> Map.Map String Variable -> IO Type
223−instantiateTypeWithContext sourceType dict = evalStateT (go sourceType) dict
224− where
225− go :: SrcT.Type -> StateT (Map.Map String Variable) IO Type
226− go sourceType =
227− case sourceType of
228− SrcT.Lambda t1 t2 -> TermN <$> (Fun1 <$> go t1 <*> go t2)
229−
230− SrcT.Var x -> do
231− dict <- get
232− case Map.lookup x dict of
233− Just var -> return (VarN var)
234− Nothing -> do
235− var <- liftIO $ namedVar x -- should this be Constant or Flexible?
236− put (Map.insert x var dict)
237− return (VarN var)
238−
239− SrcT.Data name ts -> do
240− ts' <- mapM go ts
241− return $ foldr (\t result -> TermN $ App1 t result) (error "not sure how to look this up yet") ts'
242−
243− SrcT.EmptyRecord -> return (TermN EmptyRecord1)
244−
245− SrcT.Record fields ext ->
246− TermN <$> (Record1 <$> traverse (mapM go) fields <*> go ext)
247−
248218expandPattern :: (Pattern, LExpr t v, Maybe SrcT.Type)
249219 -> [(Pattern, LExpr t v, Maybe SrcT.Type)]
250220expandPattern triple@(pattern, lexpr, maybeType) =
compiler/Type/Constrain/Literal.hs+1−1
@@ -10,7 +10,7 @@ import Type.Environment as Env
1010
1111constrain :: Environment -> Literal -> Type -> TypeConstraint
1212constrain env literal tipe =
13− let prim name = Env.get env builtin name in
13+ let prim name = Env.get env Env.types name in
1414 case literal of
1515 IntNum _ -> tipe === prim "Int"
1616 FloatNum _ -> tipe === prim "Float"
compiler/Type/Constrain/Pattern.hs+8−34
@@ -41,13 +41,15 @@ constrain env pattern tipe =
4141 }
4242
4343 PData name patterns -> do
44− (cvars, ctipe) <- freshDataScheme env name
45− let (argTypes, resultType) = flattenFunction ctipe
46− msg = "Constructor '" ++ name ++ "' expects " ++ show (length argTypes) ++ " arguments."
47− if length patterns /= length argTypes then error msg else do
48− fragment <- Monad.liftM joinFragments (Monad.zipWithM (constrain env) patterns argTypes)
44+ (kind, cvars, ctipe) <- freshDataScheme env name
45+ let tvars = map VarN cvars
46+ msg = concat [ "Constructor '", name, "' expects ", show kind
47+ , " argument", if kind == 1 then "" else "s"
48+ , " but was given ", show (length patterns), "." ]
49+ if length patterns /= kind then error msg else do
50+ fragment <- Monad.liftM joinFragments (Monad.zipWithM (constrain env) patterns tvars)
4951 return $ fragment {
50− typeConstraint = typeConstraint fragment /\ tipe === resultType,
52+ typeConstraint = typeConstraint fragment /\ tipe === ctipe,
5153 vars = cvars ++ vars fragment
5254 }
5355
@@ -60,31 +62,3 @@ constrain env pattern tipe =
6062 vars = map snd pairs,
6163 typeConstraint = c
6264 }
63−
64−freshDataScheme :: Environment -> [Char] -> IO ([Variable], Type)
65−freshDataScheme env name =
66− do let (vars, tipe) = Env.get env constructor name
67− freshVars <- mapM (\_ -> flexibleVar) vars
68− let assocList = zip vars freshVars
69− return (freshVars, substitute assocList tipe)
70−
71−substitute :: Eq a => [(a, a)] -> TermN a -> TermN a
72−substitute assocs tipe =
73− case tipe of
74− VarN x -> VarN (Maybe.fromMaybe x (List.lookup x assocs))
75− TermN t -> TermN $
76− case t of
77− App1 a b -> App1 (substitute assocs a) (substitute assocs b)
78− Fun1 a b -> Fun1 (substitute assocs a) (substitute assocs b)
79− Var1 v -> Var1 (substitute assocs v)
80− EmptyRecord1 -> EmptyRecord1
81− Record1 fields extension ->
82− Record1 (Map.map (map $ substitute assocs) fields)
83− (substitute assocs extension)
84−
85−flattenFunction :: TermN t -> ([TermN t], TermN t)
86−flattenFunction = go []
87− where go args tipe =
88− case tipe of
89− TermN (Fun1 a b) -> go (a:args) b
90− _ -> (reverse args, tipe)
compiler/Type/Environment.hs+114−22
@@ -1,41 +1,133 @@
11module Type.Environment where
22
3+import Control.Applicative ((<$>), (<*>))
4+import Control.Monad
5+import qualified Control.Monad.State as State
6+import qualified Data.Traversable as Traverse
37import qualified Data.Map as Map
48import Data.Map ((!))
59import qualified Data.UnionFind.IO as UF
610
11+import qualified SourceSyntax.Type as Src
712import Type.Type
813
914data Environment = Environment {
10− constructor :: Map.Map String ([Variable], Type),
11− builtin :: Map.Map String Type,
15+ constructor :: Map.Map String (IO (Int, [Variable], Type)),
16+ types :: Map.Map String Type,
1217 value :: Map.Map String Type
1318}
1419
15−initialEnvironment :: IO Environment
16−initialEnvironment = do
17− let mkPair name = fmap ((,) name . VarN) (namedVar name)
18− list <- mkPair "[_]"
19− int <- mkPair "Int"
20− prims <- mapM mkPair ["Float","Char","Bool","Element"]
21− let builtins = list : int : prims
22−
23− cons <- do v <- flexibleVar
24− let vlist = TermN (App1 (snd list) (VarN v))
25− return ([v], VarN v ==> vlist ==> vlist)
26−
27− nil <- do v <- flexibleVar
28− return ([v], TermN (App1 (snd list) (VarN v)))
29−
30− let add = snd int ==> snd int ==> snd int
20+initialEnvironment :: [(String, [String], [(String,[Src.Type])])] -> IO Environment
21+initialEnvironment datatypes = do
22+ types <- makeTypes datatypes
3123
3224 return $ Environment {
33− constructor = Map.fromList [("::", cons), ("[]", nil)],
34− builtin = Map.fromList builtins,
35− value = Map.empty -- Map.fromList [("+", add)]
25+ constructor = makeConstructors types datatypes,
26+ types = types,
27+ value = Map.empty
3628 }
3729
30+makeTypes datatypes =
31+ Map.fromList <$> mapM makeCtor (builtins ++ map nameAndKind datatypes)
32+ where
33+ nameAndKind (name, tvars, _) = (name, length tvars)
34+
35+ makeCtor (name, kind) = do
36+ ctor <- VarN <$> namedVar name
37+ return (name, ctor)
38+
39+ tuple n = ("_Tuple" ++ show n, n)
40+
41+ kind n names = map (\name -> (name, n)) names
42+
43+ builtins :: [(String,Int)]
44+ builtins = concat [ map tuple [0..10]
45+ , kind 1 ["_List","Maybe","Signal"]
46+ , kind 0 ["Int","Float","Char","Bool","Element"]
47+ ]
48+
49+makeConstructors types datatypes =
50+ Map.union (Map.fromList builtins) (Map.unions $ map (instances dummyEnv) datatypes)
51+ where
52+ dummyEnv = Environment { constructor=Map.empty, types=types, value=Map.empty }
53+
54+ list t = (types ! "_List") <| t
55+ maybe t = (types ! "Maybe") <| t
56+
57+ inst :: Int -> Int -> ([Type] -> Type) -> IO (Int, [Variable], Type)
58+ inst kind numTVars tipe = do
59+ vars <- forM [1..numTVars] $ \_ -> flexibleVar
60+ return (kind, vars, tipe $ map VarN vars)
61+
62+ tupleCtor n =
63+ let name = "_Tuple" ++ show n
64+ in (name, inst n n $ \vs -> foldr (==>) (foldl (<|) (types ! name) vs) vs)
65+
66+ builtins :: [ (String, IO (Int, [Variable], Type)) ]
67+ builtins = [ ("Nothing", inst 0 1 $ \ [t] -> maybe t)
68+ , ("Just" , inst 1 1 $ \ [t] -> t ==> maybe t)
69+ , ("[]" , inst 0 1 $ \ [t] -> list t)
70+ , ("::" , inst 2 1 $ \ [t] -> t ==> list t ==> list t)
71+ ] ++ map tupleCtor [0..10]
72+
73+
74+
3875get :: Environment -> (Environment -> Map.Map String a) -> String -> a
3976get env subDict key = Map.findWithDefault err key (subDict env)
4077 where
41− err = error $ "Could not find '" ++ key ++ "' in the type environment."
78+ err = error $ "Could not find '" ++ key ++ "' in the type environment."
79+
80+
81+freshDataScheme :: Environment -> String -> IO (Int, [Variable], Type)
82+freshDataScheme env name = do
83+ putStr "fresh " >> putStrLn name
84+ get env constructor name
85+
86+
87+instances :: Environment
88+ -> (String, [String], [(String, [Src.Type])])
89+ -> Map.Map String (IO (Int, [Variable], Type))
90+instances env (name, tvars, ctors) = Map.fromList $ map go ctors
91+ where
92+ tipe = Src.Data name (map Src.Var tvars)
93+
94+ go (ctor, tipes) = (,) ctor $ do
95+ let funcType = foldr Src.Lambda tipe tipes
96+ (vars, ttype) <- instantiateTypeWithContext env funcType Map.empty
97+ return (length tipes, vars, ttype)
98+
99+instantiateType :: Environment -> Src.Type -> IO Type
100+instantiateType env sourceType =
101+ snd <$> instantiateTypeWithContext env sourceType Map.empty
102+
103+instantiateTypeWithContext :: Environment
104+ -> Src.Type
105+ -> Map.Map String Variable
106+ -> IO ([Variable], Type)
107+instantiateTypeWithContext env sourceType dict =
108+ do (tipe, dict') <- State.runStateT (go sourceType) dict
109+ return (Map.elems dict', tipe)
110+ where
111+ go :: Src.Type -> State.StateT (Map.Map String Variable) IO Type
112+ go sourceType =
113+ case sourceType of
114+ Src.Lambda t1 t2 -> TermN <$> (Fun1 <$> go t1 <*> go t2)
115+
116+ Src.Var x -> do
117+ dict <- State.get
118+ case Map.lookup x dict of
119+ Just var -> return (VarN var)
120+ Nothing -> do
121+ var <- State.liftIO $ namedVar x -- should this be Constant or Flexible?
122+ State.put (Map.insert x var dict)
123+ return (VarN var)
124+
125+ Src.Data name ts -> do
126+ State.liftIO $ putStr "instantiate " >> putStrLn name
127+ ts' <- mapM go ts
128+ return $ foldr (\t result -> TermN $ App1 t result) (get env types name) ts'
129+
130+ Src.EmptyRecord -> return (TermN EmptyRecord1)
131+
132+ Src.Record fields ext ->
133+ TermN <$> (Record1 <$> Traverse.traverse (mapM go) fields <*> go ext)
compiler/Type/Inference.hs+12−2
@@ -13,17 +13,27 @@ import qualified SourceSyntax.Expression as Expr
1313import Text.PrettyPrint
1414import qualified Type.State as TS
1515import Control.Monad.State
16+import Control.Arrow (second)
1617import Transform.SortDefinitions as Sort
1718
1819import System.IO.Unsafe -- Possible to switch over to the ST monad instead of
1920 -- the IO monad. Not sure if that'd be worthwhile.
2021
22+
2123infer :: MetadataModule t v -> Either [Doc] (Map.Map String T.Variable)
2224infer modul = unsafePerformIO $ do
23− env <- Env.initialEnvironment
25+ env <- Env.initialEnvironment (datatypes modul)
2426 var <- T.flexibleVar
27+ ctors <- forM (Map.keys (Env.constructor env)) $ \name ->
28+ do (_, vars, tipe) <- Env.freshDataScheme env name
29+ return (name, (vars, tipe))
30+
2531 let expr = Expr.dummyLet $ defs modul
26− constraint <- TcExpr.constrain env expr (T.VarN var)
32+ vars = concatMap (fst . snd) ctors
33+ header = Map.map snd (Map.fromList ctors)
34+ environ = T.CLet [ T.Scheme vars [] T.CTrue header ]
35+ constraint <- environ `fmap` TcExpr.constrain env expr (T.VarN var)
36+ print =<< T.extraPretty constraint
2737 (env,_,_,errors) <- execStateT (Solve.solve constraint) TS.initialState
2838 if null errors
2939 then return $ Right env