-generalize env t = Scheme (difference (ftv t) (ftv env)) t
-
-:: TI a :== RWST TIEnv () TIState (Either [String]) a
-:: TIState = {tiSupply :: Int, tiSubst :: Subst}
-:: TIEnv :== [Int]
-
-mgu :: Type Type -> TI Subst
-mgu (TFun l r) (TFun l` r`) = composeSubst <$> mgu l l` <*> mgu r r`
-mgu (TVar u) t = varBind u t
-mgu t (TVar u) = varBind u t
-mgu TInt TInt = pure 'DM'.newMap
-mgu TBool TBool = pure 'DM'.newMap
-mgu TChar TChar = pure 'DM'.newMap
-mgu t1 t2 = liftT (Left ["cannot unify: " +++ toString t1 +++ " with " +++ toString t2])
-
-varBind :: [Char] Type -> TI Subst
-varBind u t
- | t == TVar u = pure 'DM'.newMap
- | isMember u (ftv t) = liftT (Left ["occur check fails: " +++ toString u +++ " vs. " +++ toString t])
- = pure ('DM'.singleton u t)
-
-newTyVar :: [Char] -> TI Type
-newTyVar prefix
- = get
- >>= \t->put {t & tiSupply=t.tiSupply+1}
- >>| pure (TVar (prefix ++ fromString (toString t.tiSupply)))
-
-instantiate :: Scheme -> TI Type
-instantiate (Scheme vars t)
- = mapM (\_->newTyVar ['a']) vars
- >>= \nvars->pure (apply ('DM'.fromList (zip2 vars nvars)) t)
-
-class infer a :: TypeEnv a -> TI (Subst, Type)
-
-instance infer Value where
- infer _ (Int _) = pure ('DM'.newMap, TInt)
- infer _ (Bool _) = pure ('DM'.newMap, TBool)
- infer _ (Char _) = pure ('DM'.newMap, TChar)
-
-instance infer Expression where
- infer e (Lit a) = infer e a
- infer (TypeEnv env) (Var v) = case 'DM'.get v env of
- Nothing = liftT (Left ["unbound variable: " +++ toString v])
- Just s = instantiate s >>= \t->pure ('DM'.newMap, t)
- infer env (App e1 e2)
- = newTyVar ['a']
- >>= \tv ->infer env e1
- >>= \(s1, t1)->infer (apply s1 env) e2
- >>= \(s2, t2)->mgu (apply s2 t1) (TFun t2 tv)
- >>= \s3->pure (composeSubst s3 (composeSubst s2 s1), apply s3 tv)
- infer env (Lambda s e)
- = newTyVar ['l']
- >>= \tv->
- let (TypeEnv env`) = remove env s
- env`` = TypeEnv ('DM'.union env` ('DM'.singleton s (Scheme [] tv)))
- in infer env`` e
- >>= \(s1, t1)->pure (s1, TFun (apply s1 tv) t1)
-
-instance infer [Function] where
- infer env [] = pure ('DM'.newMap, TInt)
- infer env [Function name args body:rest]
- = infer env (foldr Lambda body args) >>= \(s1, t1)->
- let (TypeEnv env`) = remove env name
- t` = generalize (apply s1 env) t1
- env`` = TypeEnv ('DM'.put name t` env`)
- in infer (apply s1 env``) rest >>= \(s2, t2)->pure (composeSubst s1 s2, t2)
-
-typeInference :: ('DM'.Map [Char] Scheme) Expression -> TI Type
-typeInference env e = uncurry apply <$> infer (TypeEnv env) e
+generalize env t = Forall (difference (ftv t) (ftv env)) t
+
+//:: Expression
+// = Lit Value
+// | Var [Char]
+// | App Expression Expression
+// | Lambda [Char] Expression
+// | Builtin [Char] [Expression]
+inferExpr :: TypeEnv Expression -> Either [String] Scheme
+inferExpr env ex = case runRWST (infer ex) env {count=0} of
+ Left e = Left e
+ Right (ty, st, cs) = case runStateT solver ('DM'.newMap, cs) of
+ Left e = Left e
+ Right (s, _) = Right (closeOver (apply s ty))
+
+closeOver :: Type -> Scheme
+closeOver t = normalize (generalize 'DM'.newMap t)
+
+normalize :: Scheme -> Scheme
+normalize t = t
+
+inferAST :: TypeEnv [Function] -> Either [String] TypeEnv
+inferAST env [] = Right env
+inferAST env [Function name args body:rest] = case inferExpr env (foldr Lambda body args) of
+ Left e = Left e
+ Right ty = inferAST ('DM'.put name ty env) rest
+
+inferFunc :: [Function] -> Infer ()
+inferFunc [] = pure ()
+inferFunc [Function name args body:rest]
+ = ask
+ >>= \en->infer (foldr Lambda body args)
+ >>= \t1->inEnv (name, generalize en t1) (inferFunc rest)
+ >>= \_->pure ()
+
+infer :: Expression -> Infer Type
+infer (Lit v) = case v of
+ Int _ = pure TInt
+ Bool _ = pure TBool
+ Char _ = pure TChar
+infer (Var s) = asks ('DM'.get s)
+ >>= maybe (liftT $ Left ["Unbound variable " +++ toString s]) instantiate
+infer (App e1 e2)
+ = infer e1
+ >>= \t1->infer e2
+ >>= \t2->fresh
+ >>= \tv->uni t1 (TFun t2 tv)
+ >>| pure tv
+infer (Lambda s e)
+ = fresh
+ >>= \tv->inEnv (s, Forall [] tv) (infer e)
+ >>= \t-> pure (TFun tv t)
+//infer (Let x e1 e2)
+// = ask
+// >>= \en->infer e1
+// >>= \t1->inEnv (x, generalize en t1) (infer e2)
+
+unifies :: Type Type -> Solve Unifier
+unifies TInt TInt = pure ('DM'.newMap, [])
+unifies TBool TBool = pure ('DM'.newMap, [])
+unifies TChar TChar = pure ('DM'.newMap, [])
+unifies (TVar a) (TVar b)
+ | a == b = pure ('DM'.newMap, [])
+unifies (TVar v) t = tbind v t
+unifies t (TVar v) = tbind v t
+unifies (TFun t1 t2) (TFun t3 t4) = unifyMany [t1, t2] [t3, t4]
+unifies t1 t2 = liftT $ Left ["Cannot unify " +++ toString t1 +++ " with " +++ toString t2]
+
+unifyMany :: [Type] [Type] -> Solve Unifier
+unifyMany [] [] = pure ('DM'.newMap, [])
+unifyMany [t1:ts1] [t2:ts2] = unifies t1 t2
+ >>= \(su1, cs1)->unifyMany (apply su1 ts1) (apply su1 ts2)
+ >>= \(su2, cs2)->pure (su2 `compose` su1, cs1 ++ cs2)
+unifyMany t1 t2 = liftT $ Left ["Length difference in unifyMany"]
+
+(`compose`) infix 1 :: Subst Subst -> Subst
+(`compose`) s1 s2 = 'DM'.union (apply s1 <$> s2) s1
+
+tbind :: [Char] Type -> Solve Unifier
+tbind a (TVar b)
+ | a == b = pure ('DM'.newMap, [])
+tbind a t
+ | occursCheck a t = liftT $ Left ["Infinite type " +++ toString a +++ toString t]
+ = pure $ ('DM'.singleton a t, [])
+
+occursCheck :: [Char] a -> Bool | Substitutable a
+occursCheck a t = isMember a $ ftv t
+
+solver :: Solve Subst
+solver = getState >>= \(su, cs)->case cs of
+ [] = pure su
+ [(t1, t2):cs0] = unifies t1 t2
+ >>= \(su1, cs1)->'MS'.put (su1 `compose` su, cs1 ++ (apply su1 cs0))
+ >>| solver