module Text.Roundtrip.Printer (
Printer(..),
printerApply, printerConcat, printerAlternative, printerEmpty,
printerPure, runPrinter, runStringPrinter
) where
import Control.Monad.Identity (Identity, runIdentity)
import Data.Monoid
import Text.Roundtrip
newtype Printer m r a = Printer { unPrinter :: a -> m (Maybe r) }
instance Monad m => IsoFunctor (Printer m r) where
(<$>) = printerApply
printerApply :: Monad m => Iso a b -> Printer m r a -> Printer m r b
printerApply iso (Printer p) = Printer $ \b ->
case unapply iso b of
Just x -> p x
Nothing -> return Nothing
instance (Monad m, Monoid r) => ProductFunctor (Printer m r) where
(<*>) = printerConcat
printerConcat :: (Monoid r, Monad m) => Printer m r a -> Printer m r b -> Printer m r (a, b)
printerConcat (Printer p) (Printer q) = Printer $ \(a, b) ->
do ma <- p a
case ma of
Nothing -> return Nothing
Just !ea -> do mb <- q b
case mb of
Nothing -> return Nothing
Just eb -> return (Just (ea `mappend` eb))
instance Monad m => Alternative (Printer m r) where
(<|>) = printerAlternative
(<||>) = printerAlternative
empty = printerEmpty
printerEmpty :: Monad m => Printer m r a
printerEmpty = Printer $ \_ -> return Nothing
printerAlternative :: Monad m => Printer m r a -> Printer m r a -> Printer m r a
printerAlternative (Printer p) (Printer q) = Printer $ \a ->
do ma <- p a
case ma of
Nothing -> q a
Just ea -> return (Just ea)
instance (Monad m, Monoid r) => Syntax (Printer m r) where
pure = printerPure
printerPure :: (Monad m, Monoid r, Eq a) => a -> Printer m r a
printerPure x = Printer $ \y -> if x == y then return (Just mempty) else return Nothing
instance Monad m => StringSyntax (Printer m String) where
token f = Printer $ \c -> return (if f c then Just [c] else Nothing)
runPrinter :: Printer Identity r a -> a -> Maybe r
runPrinter (Printer p) x = runIdentity (p x)
runStringPrinter :: Printer Identity String a -> a -> Maybe String
runStringPrinter = runPrinter