content: module Util.VarName(
      VarNameT(),
      VarName(),
      runVarNameT,
      runVarName,
      newName,
      subVarName,
      lookupName,
      maybeLookupName,
      newLookupName) where
  
  import Control.Monad.State
  import Control.Monad.Identity
  import qualified Data.Map as Map
  
  newtype VarNameT nc ni no m a = VarName (StateT (Map.Map ni no, Map.Map nc Int) m a)
      deriving(Monad, MonadTrans, Functor, MonadFix, MonadPlus, MonadIO)
  
  type VarName ni no a = VarNameT () ni no Identity a
  
  
  runVarNameT :: Monad m => VarNameT nc ni no m a -> m a
  runVarNameT  (VarName sm) = evalStateT sm (Map.empty, Map.empty)
  
  runVarName ::  VarName ni no a -> a
  runVarName v = runIdentity $ runVarNameT v
  
  subVarName ::  Monad m => VarNameT nc ni no m a -> VarNameT nc ni no m a
  subVarName (VarName action) = VarName $ do
      x <- get
      r <- action
      put x
      return r
  
  
  newName :: (Ord ni, Ord nc,Monad m) => [no] -> nc -> ni -> VarNameT nc ni no m no
  newName ns nc ni = VarName $ do
      (nim,ncm) <- get
      let no = ns!!i
          Just i = fmap (subtract 1) $ Map.lookup nc ncm'
          ncm' = Map.insertWith' (+) nc 1 ncm
      put (Map.insert ni no nim, ncm')
      return no
  
  lookupName :: (Ord ni, Monad m,Show ni) => ni -> VarNameT nc ni no m no
  lookupName t = VarName $ do
      (nim,_) <- get
      case Map.lookup t nim of
          Just x -> return x
          Nothing -> fail $ "lookupName not found: " ++ show t
  
  maybeLookupName :: (Ord ni, Monad m,Show ni) => ni -> VarNameT nc ni no m (Maybe no)
  maybeLookupName t = VarName $ do
      (nim,_) <- get
      case Map.lookup t nim of
          Just x -> return (Just x)
          Nothing -> return $ fail $ "lookupName not found: " ++ show t
  
  newLookupName :: (Ord ni, Ord nc,Monad m) => [no] -> nc -> ni -> VarNameT nc ni no m no
  newLookupName ns nc ni = VarName $ do
      (nim,ncm) <- get
      case Map.lookup ni nim of
          Just x -> return x
          Nothing -> do
              let no = ns!!i
                  Just i = fmap (subtract 1) $ Map.lookup nc ncm'
                  ncm' = Map.insertWith' (+) nc 1 ncm
              put (Map.insert ni no nim, ncm')
              return no
  
  
  
  