-- 
-- (C) Susumu Katayama
--
module MagicHaskeller.Analytical.UniT where

import Control.Monad -- hiding (guard)
import Control.Monad.State -- hiding (guard)

import MagicHaskeller.Analytical.Syntax

type UniT  = StateT St
data St    = St {subst::Subst, nextVar :: Int} deriving Show

emptySt = St {subst=[], nextVar=0}

freshVar :: Monad m => UniT m Expr
freshVar = do st <- get
              let nv = nextVar st
              put st{nextVar = succ nv}
              return $ E nv
freshIOP (IOP n ins out) = do st <- get
                              let nv = nextVar st
                              put st{nextVar = nv + n}
                              return $ IOP 0 (map (fresh (nv+)) ins) (fresh (nv+) out)

applyUT :: Monad m => Expr -> UniT m Expr
applyUT ex = do s <- gets subst
                return $ apply s ex
applyIOPUT iop = do s <- gets subst
                    return $ applyIOP s iop
 
unifyUT :: MonadPlus m => Expr -> Expr -> UniT m ()
unifyUT e1 e2 = case unify e1 e2 of Just s  -> modify (\st -> st{subst = s `plusSubst` subst st})
                                    Nothing -> mzero
{- Obviously this is slower, but I do not remember why I used this.
unifyUT e1 e2 = do s <- unify e1 e2
                   modify (\st -> st{subst = s `plusSubst` subst st})
-}
appUnifyUT e1 e2 = do s <- gets subst
                      unifyUT (apply s e1) (apply s e2)
