[Haskell-cafe] Reading from a process

Mitar mmitar at gmail.com
Wed Dec 16 15:19:09 EST 2009


I would like to make an one-directional inter-process communication in
a way that one process is printing out read-compatible Haskell data
types and Haskell program is reading them from a pipe. I would like to
make a function which would return Nothing if there is no data type in
a pipe or Just last data type there was in a pipe (discarding all
before). So it should behave in a non-blocking way.

In an attempt I made this:

getLastMyData :: MyState (Maybe MyData)
getLastMyData = do
  p <- gets process
  case p of
    Nothing                                              -> fail "No process"
    Just (MyProcess processOut processPid processBuffer) -> do
      processRunning <- io $ getProcessExitCode processPid
      case processRunning of
        Just _ -> processExited
        _      -> do
          ret <- io $ tryJust (guard . isEOFError) $ slurpInput
processOut processBuffer
          case ret of
            Left _              -> processExited -- EOF
            Right currentBuffer -> do
              let (datalist, currentBuffer') = readData currentBuffer
              modify (\s -> s { process = Just (MyProcess processOut
processPid currentBuffer') })
              if null datalist
                then return Nothing
                else return $ Just $ head datalist -- MyData is stored
in the reverse order so head is the last MyData from the process

slurpInput :: Handle -> String -> IO String
slurpInput h buffer = do
  ready <- hReady h
  if not ready
    then return buffer
    else do
      char <- hGetChar h
      slurpInput h (buffer ++ [char])

readData :: String -> ([MyData], String)
readData buffer = readData' [] buffer
  where readData' datalist []  = (datalist, [])
        readData' datalist buf = case reads buf of
                                   [(x, rest)] -> readData' ((head
x):datalist) rest -- x is a list and currently it has only one element
                                   []          -> if length buf > 5 *
                                                    then error
"Invalid data from process"
                                                    else (datalist,
buf) -- we probably do not have enough data to read MyData properly
                                   _           -> error "Ambiguous
parse from process"

(I have cleaned a code somewhat, I hope I have not introduced any
errors. MyData is encapsulated in a list when printed from a process,
this is why is there "head".)

The problem is that I do not like this approach. And it does not look
nice. For example I am reading byte per byte and appending it to the
end. Then the problem is that if process is sending garbage faster
then Haskell can consume it Haskell stays in slurpInput function and
never gets to readData where it would found out that there is garbage
coming in. I could use hGetBufNonBlocking? But it would still not
solve garbage problem.

So is there some better way to do it?


More information about the Haskell-Cafe mailing list