This is a toy parser monad written to be compatible with the standard Read and ReadS framework. As such, it is not intended to be fast. :) > module ReaderMonad(module ReaderMonad, MonadPlus(..)) where > import Monad(MonadPlus(..)) The reader type: just a wrapper around a ReadS function. > newtype Reader a = Reader (ReadS a) The wrapper around reads: > reader :: Read a => Reader a > reader = Reader reads To recover the ReadS function: > toReadS (Reader r) = r Make it into a state-threading, non-deterministic (backtracking) monad so we can combine readers with ease in the do notation. > instance Monad Reader where > return x = Reader (\s -> [(x,s)]) > (Reader r) >>= g = Reader (\s -> do {(a,t) <- r s; toReadS (g a) t}) > fail _ = Reader (\s -> []) Furthermore, make it into a monad with a zero and a plus, so we have a notion of (non-deterministic) choice. This is slow when we do not need the non-determinism, but what the heck. > instance MonadPlus Reader where > mzero = Reader (\s -> []) > mplus (Reader r1) (Reader r2) = Reader (\s -> r1 s ++ r2 s) If you really want deterministic, non-commutative choice (choose the first one that succeeds, and discard the rest), use this in place of mplus: > mcut (Reader r1) (Reader r2) = Reader (\s -> r1 s +++ r2 s) > where [] +++ t = t > s +++ t = s A skip reader: skips everything in the input string, to satisfy read and friends. Non-strict (good thing). > skip :: ReadS () > skip _ = [((),"")] > skipper :: Reader () > skipper = Reader skip Lastly, some mockery of read, readIO, and readLn so that you don't always need a Read instance. (Just provide a ReadS function or a Reader.) > rsread :: ReadS a -> String -> a > rsread r s = case [x | (x,t) <- r s, ("","") <- lex t] > of [x] -> x > [] -> error "ReaderMonad: no parse" > _ -> error "ReaderMonad: ambiguous parse" > rread :: Reader a -> String -> a > rread (Reader r) = rsread r > rsreadIO :: ReadS a -> String -> IO a > rsreadIO r s = case [x | (x,t) <- r s, ("","") <- lex t] > of [x] -> return x > [] -> ioError (userError "ReaderMonad: no parse") > _ -> ioError (userError "ReaderMonad: ambiguous parse") > rreadIO :: Reader a -> String -> IO a > rreadIO (Reader r) = rsreadIO r > rsreadLn :: ReadS a -> IO a > rsreadLn r = do l <- getLine > rsreadIO r l > rreadLn :: Reader a -> IO a > rreadLn (Reader r) = rsreadLn r Example 1: read a line containing an integer n, then read n lines, each containing integers x, y, z. Print the list of these triplets. main = do n <- readLn ts <- sequence (replicate n readTriplet) print ts readTriplet :: IO (Int,Int,Int) readTriplet = do l <- getLine rreadIO r l where r = do x <- reader y <- reader z <- reader return (x,y,z)