How to implement "parsec" for channels?

I wrote a Conduitthat generates a stream of elements. These elements are of a custom type (say, Record), and each of them contains some structured data. I am trying to write a downstream Conduitthat parses Record-stream.

Interestingly, there are a lot of concepts in the parsec package in my application . For example, I sometimes expect to manywrite that a satisfyparticular predicate is on a line, or maybe I expect that exactly one instance of a particular record will appear immediately after one other specific record. So I was looking for ways to override these functions for Conduit, for example,

satisfy :: Monad m => (r -> Bool) -> ConduitM r a m rp
many :: Monad m => ConduitM r a m rp -> ConduitM r a m [rp]
sepBy :: Monad m => ConduitM r a m rp -> ConduitM r a m sep -> ConduitM r a m [rp]

which specializes in them in the above example

satisfy :: (Record -> Bool) -> ConduitM Record () IO Record
many :: ConduitM Record () IO Record -> ConduitM Record () IO [Record]
sepBy :: ConduitM Record () IO Record -> ConduitM Record () IO Record -> ConduitM Record a IO [Record]

so that I can write neat code, for example:

parserC :: Sink Record IO (Record, [Record], [Record])
parserC = do
    red <- satisfy isRecordRed
    blues <- many $ satisfy isRecordBlue
    assorted <- anyRecord `sepBy` satisfy isRecordPurple
    return (red, blues, assorted)

Now, looking at the parsec documentation, I found that these functions are actually defined for a very general class Stream. Therefore, I think that connection to the package should be possible. However, one difficulty I came across is that the function parseworks with the whole thread s. Is there a way to parse in a parsecTstreaming way?

+4
source share

Source: https://habr.com/ru/post/1613575/


All Articles