atp-0.1.0.0: src/ATP/Internal/Enumeration.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-|
Module : ATP.Internal.Enumeration
Description : The helper Enumeration monad used to describe computations that
carry on a renaming of values to consecutive numbers.
Copyright : (c) Evgenii Kotelnikov, 2019-2021
License : GPL-3
Maintainer : evgeny.kotelnikov@gmail.com
Stability : experimental
-}
module ATP.Internal.Enumeration (
EnumerationT(..),
evalEnumerationT,
Enumeration,
evalEnumeration,
next,
enumerate,
alias
) where
import Control.Monad.State (MonadTrans, MonadState, StateT, evalStateT, gets, modify)
import Data.Functor.Identity (Identity(..))
import Data.Map (Map)
import qualified Data.Map as M (empty, lookup, insert)
newtype EnumerationT a m s = EnumerationT {
runEnumerationT :: StateT (Integer, Map a Integer) m s
} deriving (Functor, Applicative, Monad, MonadTrans, MonadState (Integer, Map a Integer))
evalEnumerationT :: Monad m => EnumerationT a m e -> m e
evalEnumerationT e = evalStateT (runEnumerationT e) (1, M.empty)
type Enumeration a = EnumerationT a Identity
evalEnumeration :: Enumeration a e -> e
evalEnumeration = runIdentity . evalEnumerationT
next :: Monad m => EnumerationT a m Integer
next = do
i <- gets fst
modify $ \(j, m) -> (j + 1, m)
return i
enumerate :: (Ord a, Monad m) => a -> EnumerationT a m Integer
enumerate v = gets (M.lookup v . snd) >>= \case
Just w -> return w
Nothing -> do
i <- next
modify $ fmap (M.insert v i)
return i
alias :: (Ord a, Monad m) => a -> a -> EnumerationT a m ()
alias a b = gets (\(_, m) -> (M.lookup a m, M.lookup b m)) >>= \case
(Just i, Nothing) -> modify $ fmap (M.insert b i)
(Nothing, Just i) -> modify $ fmap (M.insert a i)
(_, _) -> do
i <- next
modify $ fmap (M.insert a i)
modify $ fmap (M.insert b i)