1

コンジット ソースを介して HTTP からデータをストリーミングするコンジットを作成しようとしています。これが私がこれまでに持っているものです:

import qualified Network.HTTP.Client.Conduit as CC

getStream :: String -> IO (ConduitM () BS.ByteString IO ())
getStream url = do
  req <- parseUrl url
  return $  CC.withResponse req $ \res -> do
    responseBody res $= (awaitForever $ \bytes -> liftIO $ do
      putStrLn $ "Got " ++ show (BS.length bytes) ++ " but will ignore    them")

しかし、私は得ています

No instance for (Control.Monad.Reader.Class.MonadReader env0 IO) …
      arising from a use of ‘CC.withResponse’
    In the expression: CC.withResponse req
    In the second argument of ‘($)’, namely
      ‘CC.withResponse req
       $ \ res
           -> do { responseBody res $= (awaitForever $ \ bytes -> ...) }’
    In a stmt of a 'do' block:
      return
      $ CC.withResponse req
        $ \ res
            -> do { responseBody res $= (awaitForever $ \ bytes -> ...) }

MonadReaderなぜ期待されるのですか?私には意味がありません。

4

1 に答える 1

4

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

これが言っているのは、それ自体が HTTP マネージャーにアクセスする方法を持つm何らかのタイプのリーダー環境を持っているということです。env

特に、エラーメッセージが不平を言っているのはm、単純なモナドだけではありません。IO

コメントでの質問への回答

ProducerHTTP 応答からを作成する方法の例を次に示します。

{-# 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
于 2016-04-30T03:45:49.437 に答える