Question

I've been playing with the Control.Proxy.TCP library and would like to to create a Producer from a network source.

producer :: Proxy p => HostName -> ServiceName -> () -> Producer p BS.ByteString IO ()
producer h p () = runIdentityP $
    lift $ connect h p $ \(s, r) ->
        runProxy $ nsocketReadS s >-> pxy >-> socketWriteD s
    where
        pxy () = runIdentityP $ do
            respond "resource-id" -- ask for "resource-id"
            bs <- request 1024    -- fetch up to 1024 bytes
            lift $ respond bs     -- and produce them from the outer proxy
            return ()

The code above does not type check:

Couldn't match type `p0 a'0 a1 a0 BS.ByteString m0' with `IO'
Expected type: ()
               -> ProxyFast Int BS.ByteString () BS.ByteString IO ()
  Actual type: ()
               -> ProxyFast
                    Int
                    BS.ByteString
                    ()
                    BS.ByteString
                    (p0 a'0 a1 a0 BS.ByteString m0)
                    ()
In the second argument of `(>->)', namely `pxy'
In the first argument of `(>->)', namely `nsocketReadS s >-> pxy'
In the second argument of `($)', namely
  `nsocketReadS s >-> pxy >-> socketWriteD s'

I see that the base monad for nsocketReadS and socketWriteD is IO while I need a different type. How can I correct this problem?

Était-ce utile?

La solution

If you want to allocate a socket within a pipeline, you need to use the Control.Proxy.TCP.Safe module, which has the alternative version of connect that you are looking for:

connect
  :: (Proxy p, Monad m)
  => (forall x. SafeIO x -> m x)
  -> HostName
  -> ServiceName
  -> ((Socket, SockAddr) -> ExceptionP p a' a b' b m r)
  -> ExceptionP p a' a b' b m r

This uses pipes-safe to manage resource allocation within the pipeline. If you haven't used pipes-safe before then the best place to begin is the pipes-safe tutorial.

Edit: Update to answer your question in the comment. You need to hoist the socket reader and writer because their base monad is the surrounding proxy, not SafeIO.

producer
    :: (Proxy p)
    => HostName -> ServiceName
    -> () -> Producer (ExceptionP p) BS.ByteString SafeIO ()
producer h p () = connect id h p $ \(s, r) ->
    runProxy $ hoist lift . nsocketReadS s >-> pxy >-> hoist lift . socketWriteD s
  where
    pxy () = do
        respond "resource-id" -- ask for "resource-id"
        bs <- request 1024    -- fetch up to 1024 bytes
        lift $ respond bs     -- and produce them from the outer proxy
        return ()
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top