0

我正在尝试创建一个函数,该函数在给定一些参数的情况下创建一个 Source 以连接到 URL,同时在 ResourceT monad 中正确。我正在尝试以下操作:

{-# LANGUAGE OverloadedStrings #-}

import           Control.Monad.IO.Class       (liftIO)
import           Data.Conduit                 (($$), yield, unwrapResumable)
import qualified Data.Conduit.List            as CL
import           Network.HTTP.Conduit
import           Network.HTTP.Types           (methodPost)
import Control.Monad.Trans.Resource (runResourceT)

runquery manager  = do
  initreq <- parseUrl "http://localhost/test"
  let request = initreq{method=methodPost, requestBody=RequestBodyLBS "test"}
  response <- http request manager
  (httpsource, finalizer) <- unwrapResumable (responseBody response)
  httpsource
  finalizer

main = do
  manager <- newManager conduitManagerSettings
  runResourceT $ (runquery manager $$ CL.mapM_ (liftIO . print))

它不起作用,我从编译器收到“无法构造无限类型”错误。我可以return (httpsource,finalizer)(或只是整个 responseBody)稍后再使用它,但在我看来这很奇怪。编写此代码的正确方法是什么,为什么会出现无限类型错误?

如果没有类型签名,我会收到以下错误:

test.hs:17:3:
    Occurs check: cannot construct the infinite type:
      m
      ~
      conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
        () ByteString m
    Expected type: m ()
      Actual type: Source m ByteString
    Relevant bindings include
      finalizer :: m () (bound at test.hs:16:16)
      httpsource :: Source m ByteString (bound at test.hs:16:4)
      response :: Response
                    (conduit-1.2.4:Data.Conduit.Internal.Conduit.ResumableSource
                       m ByteString)

当我添加一个签名时,(我希望应该是):

runquery :: Manager -> Source (ResourceT IO) ByteString

我收到一个错误:

Couldn't match type ‘conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
                       () ByteString (ResourceT IO)’
              with ‘ResourceT IO’
Expected type: conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
                 () ByteString (ResourceT IO) ()
  Actual type: Source
                 (conduit-1.2.4:Data.Conduit.Internal.Conduit.ConduitM
                    () ByteString (ResourceT IO))
                 ByteString

我可能正在做一些无法完成的事情,但我不太清楚问题出在哪里。

4

1 回答 1

0

unwrapResumable、http 和终结器需要在 resourceT 中运行,似乎只能在 MonadResource 上下文中工作(例如 resourceT),因此您必须将它们提升到其中。

runquery :: MonadResource m => Manager -> Source m ByteString
-- or runquery :: Manager -> Source (ResourceT IO) ByteString
runquery manager  = do
  initreq <- parseUrl "https://localhost/test"
  let request = initreq{method=methodPost, requestBody=RequestBodyLBS "test"}
  response <- lift $ http request manager
  (httpsource, finalizer) <- lift $ unwrapResumable (responseBody response)
  httpsource
  lift finalizer

main :: IO ()
main = do
  manager <- newManager conduitManagerSettings
  runResourceT $ (runquery manager $$ CL.mapM_ (liftIO . print))
于 2015-04-30T15:51:55.330 回答