我正在尝试弄清楚 Conduits 是如何工作的,并且我陷入了所涉及的 monads 和 Transformer 中。
我将一些示例代码归结为以下内容,该代码有效:
import Control.Monad.Trans.Class (lift)
import Data.Conduit
import Data.Conduit.Binary (sinkFile)
import Data.Conduit.List
import Network.HTTP.Conduit
downloadContent manager = do
mx <- await
case mx of
Nothing -> return ()
Just name -> do
req <- lift $ parseUrl $ "http://" ++ name ++ ".com/"
res <- lift $ http req manager
lift $ responseBody res $$+- sinkFile $ name ++ ".html"
downloadContent manager
main = do
runResourceT $ do
withManager $ \manager -> do
sourceList ["google", "yahoo"] $$ downloadContent manager
我不明白的是为什么我需要在
lift
里面 downloadContent
。 为什么我需要在上面的代码中使用lift
?我要从什么地方抬起来? 如果我看签名:parseUrl
:: failure-0.2.0.1:Control.Failure.Failure HttpException m =>
String -> m (Request m')
http
:: (MonadResource m, MonadBaseControl IO m) =>
Request m
-> Manager
-> m (Response
(ResumableSource m Data.ByteString.Internal.ByteString))
($$+-) :: Monad m => ResumableSource m a -> Sink a m b -> m b
downloadContent
:: (MonadResource m, MonadBaseControl IO m,
failure-0.2.0.1:Control.Failure.Failure HttpException m) =>
Manager -> ConduitM [Char] o m ()
class (MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m) => MonadResource m
这并没有真正帮助我了解正在发生的事情。
最佳答案
lift
采取未转换的 monadic 操作并将其包装起来,以便您可以在转换器中运行它:
lift :: (MonadTrans t, Monad m) => m a -> t m a
在这种情况下,转换器是
ConduitM [Char] o
,它在 Data.Conduit.Internal
中定义为:newtype ConduitM i o m r = ConduitM { unConduitM :: Pipe i i o () m r }
deriving (..., MonadTrans, ...)
它使用
MonadTrans
从 GeneralizedNewtypeDeriving
的实例派生其 Pipe
实例:instance MonadTrans (Pipe l i o u) where
lift mr = PipeM (Done `liftM` mr)
这是一个更简单的例子:
action :: ReaderT Int (State Int) ()
action = do -- In the 'ReaderT Int (State Int)' monad.
x <- ask -- Ask for the (outer) 'Reader' environment.
lift $ do -- In the 'State Int' monad.
modify (+x) -- Modify the (inner) 'State' a couple of times.
modify (+x)
main = print $ execState (runReaderT action 1) 1
我们在
ReaderT Int (State Int)
中,我们的 modify
Action 在 State Int
中,所以我们需要对 Action 进行 lift
以便在转换器中运行它。请注意,就像在上面的示例中一样,您应该能够将一系列 lift
ed 操作合并到一个 lift
下:Just name -> do
lift $ do
req <- parseUrl $ "http://" ++ name ++ ".com/"
res <- http req manager
responseBody res $$+- sinkFile $ name ++ ".html"
downloadContent manager
关于haskell - 使用ResourceT时需要提升的说明,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20623194/