\begin{code} {-# LANGUAGE TemplateHaskell #-} module Control.Edit.Container.Transducer ( ContainerTransducer{..}, ctStates , runCT, stepCT ) where import Control.Edit.Container import Data.Map.Strict (Map, (!?)) import qualified Data.Map.Strict as Map import Data.Set (Set) import qualified Data.Set as Set import Control.Monad.RWS.Strict import Control.Monad.Writer.Class import Control.Monad.Reader.Class import Control.Monad.State.Class import Control.Lens import Data.Maybe data ContainerTransducer state input output = ContainerTransducer { ctInitialState :: state , ctTransition :: Map (state, Content input) (ContainerEdits output, state) -- ^ States are stable (and produce no output) by default } ctStates :: Ord state => ContainerTransducer state input output -> Set state ctStates ContainerTransducer{..} = Map.foldrWithKey' (\(s1, _) (_, s2) -> Set.insert s1 . Set.insert s2) (Set.singleton ctInitialState) ctTransition stepCT :: ( Ord state, Ord (Content input) , MonadReader (ContainerTransducer state input output) m , MonadState state m , MonadWriter (ContainerEdits output) m ) => Content input -> m () stepCT x = do ContainerTransducer{ ctTransition } <- ask state <- get let (output, newState) = fromMaybe (mempty, state) $ ctTransition !? (state, x) put newState tell output runCT :: ( Ord state, Ord (Content input) , FoldableContainer input ) => ContainerTransducer state input output -> input -> ContainerEdits output runCT ct@ContainerTransducer{ ctInitialState } input = runRWS (forMOf_ containerContent input stepCT) ct ctInitialState ^. _3 \end{code} \begin{code} data CTComplement state input output = CTComplement { } -- Define edit-lens as span \end{code}