Как об этом изменении the example in the Network.HTTP.Conduit docs:
{-# LANGUAGE OverloadedStrings #-}
module Lib2() where
import Data.Conduit (($$+-), awaitForever)
import qualified Network.HTTP.Client.Conduit as CC
import Network.HTTP.Conduit (http, tlsManagerSettings, newManager)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Conduit.Binary (sinkFile) -- Exported from the package conduit-extra
main2 :: IO()
main2 = do
request <- CC.parseUrl "http://google.com/"
manager <- newManager tlsManagerSettings
runResourceT $ do
response <- http request manager
CC.responseBody response $$+- (awaitForever $ \x -> liftIO $ putStrLn "Chunk")
Оригинальный ответ
Возвращаемый тип getStream
неправильно. Попробуйте удалить сигнатуру и использовать FlexibleContexts
, например .:
{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
module Lib() where
import Data.Conduit
import qualified Data.ByteString as BS
import qualified Network.HTTP.Client.Conduit as CC
import Control.Monad.IO.Class
getStream url = do
req <- CC.parseUrl url
CC.withResponse req $ \res -> do
CC.responseBody res $= (awaitForever $ \x -> liftIO $ putStrLn "Got a chunk")
А затем :t getStream
отчеты:
getStream
:: (monad-control-1.0.0.4:Control.Monad.Trans.Control.MonadBaseControl
IO (ConduitM a c m),
mtl-2.2.1:Control.Monad.Reader.Class.MonadReader env m, MonadIO m,
CC.HasHttpManager env,
exceptions-0.8.0.2:Control.Monad.Catch.MonadThrow m) =>
String -> ConduitM a c m()
, который показывает, что тип возвращаемого значения имеет вид ConduitM ...
, не IO ...
.
Это также показывает, как MonadReader
попадает в картину ... Монада m
должен иметь доступ к менеджеру HTTP через среду чтения, как выражается следующими ограничениями:
CC.HasHttpManager env
MonadReader env m
Все это сказать, что m
имеет среду чтения некоторого типа env
, которая сама имеет способ доступа к HTTP-менеджеру.
В частности, m
не может быть просто равным IO
monad, о чем жалуется сообщение об ошибке.
Ответ на вопрос в комментариях
Вот пример того, как создать Producer
из ответа HTTP:
{-# LANGUAGE OverloadedStrings #-}
module Lib3() where
import qualified Data.ByteString as BS
import qualified Network.HTTP.Client.Conduit as CC
import Network.HTTP.Conduit (http, tlsManagerSettings, newManager)
import qualified Network.HTTP.Client as Client (httpLbs, responseOpen, responseClose)
import Data.Conduit (Producer, addCleanup)
import Data.Conduit (awaitForever, await, ($$))
import qualified Network.HTTP.Client.Conduit as HCC
import Control.Monad.IO.Class (liftIO, MonadIO)
getStream url = do
request <- CC.parseUrl url
manager <- newManager tlsManagerSettings
response <- Client.responseOpen request manager
let producer :: Producer IO BS.ByteString
producer = HCC.bodyReaderSource $ CC.responseBody response
cleanup _ = do liftIO $ putStrLn "(cleaning up)"; Client.responseClose response
producerWithCleanup = addCleanup cleanup producer
return $ response { CC.responseBody = producerWithCleanup }
test = do
res <- getStream "http://google.com"
let producer = CC.responseBody res
consumer = awaitForever $ \_ -> liftIO $ putStrLn "Got a chunk"
producer $$ consumer
Ого, что работает лучше, чем я ожидал. Только один вопрос: кажется, что единственный способ использовать поток «Source» - предоставить раковину в качестве аргумента. Есть ли способ фактически вернуть поток «Source», например. завернутый в 'IO'. Если не так? Алси, я не совсем понимаю, почему нужна монашеская «Монастырь». (извините, если это кажется очевидным, я все еще пытаюсь обернуть голову вокруг «Conduit») – fakedrake
Ответ обновлен - см. в конце. В 'http' функция' ResourceT' используется для вызова финализатора для ответа. Тем не менее, финализатор также добавляется в канал 'Producer' (например,' производительWithCleanup'), поэтому я не знаю, действительно ли нужно использовать 'ResourceT' - финализатор, как представляется, вызывается, даже если потребитель не потребляет все из кусков. – ErikR
Подробнее об использовании ResourceT здесь: https://github.com/snoyberg/http-client/issues/194 – ErikR