packages feed

inch-0.1.0: src/Language/Inch/Unify.lhs

> {-# LANGUAGE TypeSynonymInstances, FlexibleInstances, GADTs,
>              RankNTypes, PatternGuards #-}

> module Language.Inch.Unify where

> import Control.Applicative
> import Control.Monad hiding (mapM_)
> import Data.Foldable hiding (elem)
> import Data.List
> import Data.Maybe
> import Prelude hiding (any, mapM_)
> import Text.PrettyPrint.HughesPJ

> import Language.Inch.BwdFwd
> import Language.Inch.Kind
> import Language.Inch.Type
> import Language.Inch.TyNum
> import Language.Inch.Context
> import Language.Inch.Kit
> import Language.Inch.Error
> import Language.Inch.PrettyPrinter
> import Language.Inch.Check

> data Extension = Restore | Replace Suffix

> onTop ::  (forall k. TyEntry k -> Contextual Extension)
>             -> Contextual ()
> onTop f = do
>     c <- getContext
>     case c of
>         _Gamma :< A alphaD -> do
>             putContext _Gamma
>             ext (A alphaD) =<< f alphaD
>         _Gamma :< xD -> do
>             putContext _Gamma
>             onTop f
>             modifyContext (:< xD)
>         B0 -> erk $ "onTop: ran out of context"

> onTopNum ::  (Type KConstraint, Contextual ()) ->
>                  (TyEntry KNum -> Contextual Extension) ->
>                  Contextual ()
> onTopNum (p, m) f = do
>   g <- getContext
>   case g of
>     _Gamma :< xD -> do  
>       putContext _Gamma
>       case xD of
>         A (a@(FVar _ KNum) := d) -> ext xD =<< f (a := d)
>         Layer l True -> do
>             modifyContext (:< Layer l True)
>             m
>             modifyContext (:< Constraint Wanted p)
>         _ -> onTopNum (p, m) f >> modifyContext (:< xD)
>     B0 -> inLocation (text "when solving" <+> prettyHigh (fogSysTy p)) $
>               erk $ "onTopNum: ran out of context"

> restore :: Contextual Extension
> restore = return Restore

> replace :: Suffix -> Contextual Extension
> replace = return . Replace

> ext :: Entry -> Extension -> Contextual ()
> ext _  (Replace _Xi)  = modifyContext (<>< _Xi)
> ext xD Restore        = modifyContext (:< xD)



> unifyList :: KindI k => [Type k] -> Contextual (Type k)
> unifyList []      = unknownTyVar "_ul" kind
> unifyList (t:ts)  = mapM_ (unify t) ts >> return t


> unify :: Type k -> Type k -> Contextual ()
> unify t u = do
>     verifyContext True "unify"
>     t' <- expandTySyns t
>     u' <- expandTySyns u
>     unifyTypes t' u' `inLoc` (do
>         return $ sep [text "when unifying", nest 4 (prettyHigh $ fogSysTy t),
>                       text "and", nest 4 (prettyHigh $ fogSysTy u)])

> unifyTypes :: Type k -> Type k -> Contextual ()
> -- unifyTypes s t | s == t = return ()
> unifyTypes Arr Arr  = return ()
> unifyTypes s t | KNum <- getTyKind s = unifyNum s t
> unifyTypes (TyVar alpha) (TyVar beta) = onTop $
>   \ (gamma := d) ->
>     hetEq gamma alpha
>       (hetEq gamma beta
>         restore
>         (case d of
>           Hole      ->  replace (TE (alpha := Some (TyVar beta)) :> F0)
>           Some tau  ->  do  tau' <- expandTySyns tau
>                             unifyTypes (TyVar beta) tau'
>                             restore
>           _         ->  solve beta (TE (alpha := d) :> F0) (TyVar alpha)
>                             >> replace F0
>         )
>       )
>       (hetEq gamma beta
>         (case d of
>           Hole      ->  replace (TE (beta := Some (TyVar alpha)) :> F0)
>           Some tau  ->  do  tau' <- expandTySyns tau
>                             unifyTypes (TyVar alpha) tau'
>                             restore
>           _         ->  solve alpha (TE (beta := d) :> F0) (TyVar beta)
>                             >> replace F0
>         )
>         (unifyTypes (TyVar alpha)  (TyVar beta)  >> restore)
>       )

> unifyTypes (TyCon c1 _) (TyCon c2 _)
>     | c1 == c2   = return ()
>     | otherwise  = erk $ "Mismatched type constructors " ++ c1
>                               ++ " and " ++ c2

> unifyTypes (TyApp f1 s1) (TyApp f2 s2) =
>     hetEq (getTyKind f1) (getTyKind f2)
>         (unifyTypes f1 f2 >> unifyTypes s1 s2)
>         (erk "Mismatched kinds")

> unifyTypes (UnOp o)       (UnOp o')    | o == o' = return ()
> unifyTypes (BinOp o)      (BinOp o')   | o == o' = return ()
> unifyTypes (TyComp c)     (TyComp c')  | c == c' = return ()

> unifyTypes (TyVar alpha)  tau            = startSolve alpha tau
> unifyTypes tau            (TyVar alpha)  = startSolve alpha tau
> unifyTypes tau            upsilon        = errCannotUnify (fogTy tau) (fogTy upsilon)



> startSolve :: Var () k -> Type k -> Contextual ()
> startSolve alpha tau = do
>     (rho, xs) <- rigidHull [] tau
>     -- traceContext $ "sS\nalpha = " ++ show alpha ++ "\ntau = " ++ show tau ++ "\nrho = " ++ show rho ++ "\nxs = " ++ show xs
>     solve alpha (pairsToSuffix xs) rho
>     -- traceContext $ "sS2"
>     unifyPairs xs

> type FlexConstraint = (Var () KNum, TypeNum, TypeNum)

> makeFlex :: [Var () KNum] -> Type KNum ->
>                 Contextual (Type KNum, Fwd FlexConstraint)
> makeFlex as n = do
>     let n' = normaliseNum n
>     let (l, r) = partitionNum as n'
>     if isZero r
>         then return (n, F0)
>         else do
>             v <- freshVar SysVar "_i" KNum
>             -- traceContext $ "mF\nas = " ++ show as ++ "\nn = " ++ show n ++ "\nl' = " ++ show l' ++ "\nr' = " ++ show r'
>             return (reifyNum (mkVar v + l), (v, TyVar v, reifyNum r) :> F0)



> rigidHull :: [Var () KNum] -> Type k ->
>                  Contextual (Type k, Fwd FlexConstraint)

> rigidHull as t | KNum <- getTyKind t = makeFlex as t

> rigidHull _  (TyVar a)    = return (TyVar a, F0)
> rigidHull _  (TyCon c k)  = return (TyCon c k, F0)
> rigidHull _  Arr          = return (Arr, F0)
> rigidHull _  (UnOp o)     = return (UnOp o, F0)
> rigidHull _  (BinOp o)    = return (BinOp o, F0)
> rigidHull _  (TyComp c)   = return (TyComp c, F0)

> rigidHull as (TyApp f s)  = do  (f',  xs  )  <- rigidHull as f
>                                 (s',  ys  )  <- rigidHull as s
>                                 return (TyApp f' s', xs <.> ys)

> rigidHull as (Bind b x KNum t) = do
>     v <- freshVar SysVar "_magical" KNum
>     (t', cs) <- rigidHull (v:as) (unbindTy v t)
>     return (Bind b x KNum (bindTy v t'), cs)

> rigidHull as (Bind All x k b) | not (k =?= KNum) = do
>     v <- freshVar SysVar "_magic" k
>     (t, cs) <- rigidHull as (unbindTy v b)
>     return (Bind All x k (bindTy v t), cs)

This is wrong, I think:

> rigidHull as (Qual p t) = (\ (u, cs) -> (Qual p u, cs)) <$> rigidHull as t

> rigidHull _ b = erk $ "rigidHull can't cope with " ++ renderMe (fogSysTy b)



> pairsToSuffix :: Fwd FlexConstraint -> Suffix
> pairsToSuffix = fmap (TE . (:= Hole) . fst3)
>   where fst3 (a, _, _) = a

> unifyPairs :: Fwd FlexConstraint -> Contextual ()
> unifyPairs = mapM_ (uncurry unifyNum . snd3)
>   where snd3 (_, b, c) = (b, c)


> solve :: Var () k -> Suffix -> Type k -> Contextual ()
> solve alpha _Xi tau = onTop $
>   \ (gamma := d) -> let occurs = gamma <? tau || gamma <? _Xi in
>     hetEq gamma alpha
>       (if occurs
>          then erk $ "Occurrence of " ++ fogSysVar alpha
>                     ++ " detected when unifying with "
>                     ++ renderMe (fogTy tau)
>          else case d of
>            Hole          ->  replace (_Xi <.> (TE (alpha := Some tau) :> F0))
>            Some upsilon  ->  do  modifyContext (<>< _Xi)
>                                  upsilon' <- expandTySyns upsilon
>                                  unifyTypes upsilon' tau
>                                  restore
>            _             ->  errUnifyFixed alpha tau
>       )
>       (if occurs
>         then case d of
>           Some upsilon  ->  do
>             upsilon' <- expandTySyns upsilon
>             (upsilon'', xs) <- rigidHull [] upsilon'
>             solve alpha (pairsToSuffix xs <.> (TE (gamma := Some upsilon'') :> _Xi)) tau
>             unifyPairs xs
>             replace F0
>           _             ->  solve alpha (TE (gamma := d) :> _Xi) tau
>                                         >>  replace F0   
>         else solve alpha _Xi tau >>  restore
>       )



> unifyNum :: TypeNum -> TypeNum -> Contextual ()
> unifyNum (TyInt 0)  n = unifyZero F0 (normaliseNum n)
> unifyNum m          n = unifyZero F0 (normaliseNum (m - n))

> constrainZero :: NormalNum -> Contextual ()
> constrainZero e = modifyContext (:< Constraint Wanted (tyPred EL (reifyNum e) 0))

> unifyZero :: Suffix -> NormalNum -> Contextual ()
> unifyZero _Psi e = case getConstant e of
>   Just k  | k == 0     -> return ()
>           | otherwise  -> errCannotUnify (fogTy (reifyNum e)) (STyInt 0)
>   Nothing              -> onTopNum (tyPred EL (reifyNum e) 0, modifyContext (<>< _Psi)) $
>     \ (a := d) ->
>       case (d, solveFor a e) of
>         (Some t,  _)           -> do  modifyContext (<>< _Psi)
>                                       t' <- expandTySyns t
>                                       unifyZero F0 (substNum a t' e)
>                                       restore
>         (_,       Absent)      -> do  unifyZero _Psi e
>                                       restore
>         (Hole,    Solve n)     -> do  modifyContext (<>< _Psi)
>                                       replace $ TE (a := Some (reifyNum n)) :> F0
>         (Hole,    Simplify n)  -> do  modifyContext (<>< _Psi)
>                                       (p, b) <- insertFreshVar n
>                                       let p' = reifyNum p
>                                       unifyZero (TE (b := Hole) :> F0) $ substNum a p' e
>                                       replace $ TE (a := Some p') :> F0
>         _  | varsLeft -> do
>                          unifyZero (TE (a := d) :> _Psi) e
>                          replace F0
>            | otherwise -> do
>                modifyContext (:< A (a := d))
>                modifyContext (<>< _Psi)
>                constrainZero e
>                replace F0
>           where varsLeft = not . null $ vars e \\ (Ex a : vars _Psi)

We can insert a fresh variable into a unit thus:

> insertFreshVar :: NormalNum -> Contextual (NormalNum, Var () KNum)
> insertFreshVar d = do
>     v <- freshVar SysVar "_beta" KNum
>     return (d + mkVar v, v)



> unifyFun :: Rho -> Contextual (Sigma, Rho)
> unifyFun (TyApp (TyApp Arr s) t) = return (s, t)
> unifyFun ty = do
>     s <- unknownTyVar "_s" KSet
>     t <- unknownTyVar "_t" KSet
>     unify (s --> t) ty
>     return (s, t)