[Haskell-cafe] Parsec and network data

brian brianchina60221 at gmail.com
Tue Aug 26 16:35:28 EDT 2008


Hi, I've been struggling with this problem for days and I'm dying. Please help.

I want to use Parsec to parse NNTP data coming to me from a handle I
get from connectTo.

One unworkable approach I tried is to get a lazy String from the
handle with hGetContents. The problem: suppose the first message from
the NNTP server is "200 OK\r\n". Parsec parses it beautifully. Now I
need to discard the parsed part so that Parsec will parse whatever the
server sends next, so I use Parsec's getInput to get the remaining
data. But there isn't any, so it blocks. Deadlock: the client is
inappropriately waiting for server data and the server is waiting for
my first command.

Another approach that doesn't quite work is to create an instance of
Parsec's Stream with timeout functionality:

instance Stream Handle IO Char where
  uncons h =
    do r <- hWaitForInput h ms
       if r
         then liftM (\c -> Just (c, h)) (hGetChar h)
         else return Nothing
    where ms = 5000

It's probably obvious to you why it doesn't work, but it wasn't to me
at first. The problem: suppose you tell parsec you're looking for
(many digit) followed by (string "\r\n"). "123\r\n" won't match;
"123\n" will. My Stream has no backtracking. Even if you don't need
'try', it won't work for even basic stuff.

Here's another way:
http://www.mail-archive.com/haskell-cafe@haskell.org/msg22385.html
The OP had the same problem I did, so he made a variant of
hGetContents with timeout support. The problem: he used something from
unsafe*. I came to Haskell for rigor and reliability and it would make
me really sad to have to use a function with 'unsafe' in its name that
has a lot of wacky caveats about inlining, etc.

In that same thread, Bulat says a timeout-enabled Stream could help.
But I can't tell what library that is. 'cabal list stream' shows me 3
libraries none of which seems to be the one in question. Is Streams a
going concern? Should I be checking that out?

I'm not doing anything with hGetLine because 1) there's no way to
specify a maximum number of characters to read 2) what is meant by a
"line" is not specified 3) there is no way to tell if it read a line
or just got to the end of the data. Even using something like hGetLine
that worked better would make the parsing more obscure.

Thank you very very much for *any* help.


More information about the Haskell-Cafe mailing list