Here is the code that type-checks:
import Control.Error (fmapL)
import Control.Monad (void)
import Control.Monad.Trans.State.Strict (StateT, get)
import Data.ByteString (ByteString)
import Data.Binary.Get (Get)
import Pipes
import qualified Pipes.Prelude as P
import Pipes.Binary
data Header
data Packet
getHeader :: Get Header
getHeader = undefined
getPacket :: Get Packet
getPacket = undefined
type ParseResult = Either DecodingError
type Packets m r = Producer Packet m (ParseResult r)
parseStream
:: Monad m
=> StateT (Producer ByteString m r) m (ParseResult (Header,
Packets m r))
parseStream = do
res <- decodeGet getHeader
case res of
Left e -> return (Left e)
Right (_, h) -> do
p <- get
return $ Right
( h
, fmap (fmapL fst) $ decodeGetMany getPacket p >->
P.map snd
)
The main changes I made to your code were:
* Using `get` to retrieve the remaining input instead of `input`
* Using `fmap (fmapL fst)` to fix the `Left` return value of
`decodeGetMany` to match what you wanted
More generally, `input` is getting phased out for the next major release
of `pipes-parse`. See this thread for more details:
https://groups.google.com/forum/?fromgroups#!topic/haskell-pipes/-fsWSm26l6U
The code I wrote would remain mostly unchanged after the `pipes-parse`
update, but it would be less idiomatic. The main things that would
change is that you would simplify the type using the `Parser` type
synonym to:
parseStream
:: Monad m
=> Parse ByteString m (ParseResult (Header, Packets m r))
... and you would use `p ^. decodedL getPacket` instead of
`decodeGetMany getPacket p`.
However, the more idiomatic thing to do (both before and after the
update) would be to define the following function:
parseStream
:: Monad m
=> Producer ByteString m r
-> m (ParseResult (Header, Producer Packet m (ParseResult r)))
parseStream p = do
(res, p') <- runStateT (decodeGet getHeader) p
case res of
Left e -> return (Left e)
Right (_, h) -> do
return $ Right
( h
, fmap (fmapL fst) $ decodeGetMany getPacket p' >->
P.map snd
)
The reason why is that you don't want to keep the `ByteString` leftovers
around because they are all getting converted to `Packet`s. The only
difference is that I've removed the `StateT` layer that would
unnecessarily hold onto the `ByteString` leftovers.
On 01/18/2014 03:56 AM, Nicolas Trangez wrote:
All,
I've been trying to use pipes to tackle a problem recently, but I'm a
bit stuck.
> {-# LANGUAGE NoMonomorphismRestriction #-}
> import Pipes
> import qualified Pipes.Prelude as P
> import Pipes.Parse (input)
> import Pipes.Binary (DecodingError, Get, decodeGet, decodeGetMany)
> import Data.ByteString (ByteString)
> import Control.Monad.Trans.State.Strict (StateT, runStateT)
Here's the deal: I have an input consisting of a stream of bytes (or
`ByteString`s, more exactly):
> myInput :: Monad m => Producer' ByteString m ()
> myInput = undefined
This input is actually a `Header`, followed by zero-or-more `Packet`s.
Both have a `Get a` (as found in the `binary` package):
> data Header = Header deriving Show
> getHeader :: Get Header
> getHeader = return Header
> data Packet = Packet deriving Show
> getPacket :: Get Packet
> getPacket = return Packet
I'd like to create a function which somehow performs this parsing. It
looks like it's common to use `StateT` to provide a producer to a
parsing thing, so here's +- the type I expected to write:
> type ParseResult a = Either DecodingError a
> type Packets m r = Producer Packet m (ParseResult r)
> parseStream :: StateT (Producer ByteString m r) m (ParseResult
(Header, Packets m r))
Finally, the code I came up with (which doesn't type-check with the
above, and drives me crazy while trying to interpret the inferred type):
> parseStream = do
> res <- decodeGet getHeader
> case res of
> Left e -> return $ Left e
> Right (_, h) ->
> return $ Right (h, decodeGetMany getPacket input >->
P.map snd)
Here's what GHC infers for the above:
parseStream :: forall (m :: * -> *) r a' a r1 (m1 :: * -> *).
(Monad m, Monad m1) =>
StateT
(Producer ByteString m r)
m
(Either
DecodingError
(Header,
Proxy
a'
a
()
Packet
(StateT (Producer ByteString m1 r1) m1)
(Either
(DecodingError,
Producer ByteString (StateT (Producer
ByteString m1 r1) m1) r1)
r1)))
This doesn't feel like the above is what I'm trying to achieve.
Any pointers how to handle this situation correctly? I guess some
fidling with State* and ErrorT and whatnot would be required, but
after a fair number of attempts I can't get things aligned correctly.
Thanks,
Nicolas
--
You received this message because you are subscribed to the Google
Groups "Haskell Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to [email protected].
To post to this group, send email to [email protected].
--
You received this message because you are subscribed to the Google Groups "Haskell
Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].