haskell - 管道是否有 `liftIO` 等价物?

标签 haskell monad-transformers

我正在编写一个越来越大的管道,其中包含嵌套的 monad 转换。将每个 yieldawait 调用lift 调用到基础 conduitM 中是一项繁琐的工作。更不用说每次我添加或撤消一层转换时,我都需要在每个可能的位置更改 lift 的数量。

我一直在寻找与 liftIO 类似的功能,但不是提升 IO 操作,它应该将 yieldawait 提升到任意基于 ConduitM 转换的 monad,但我似乎找不到。有没有办法实现这样的目标?


编辑:针对@BradleyHardy的回答,我这里举一个具体的例子:

{-# LANGUAGE LambdaCase #-}

import Control.Monad                    as MON 
import Control.Monad.IO.Class           as MIO 
import Control.Monad.Trans.Class        as MTC 
import Control.Monad.Trans.Maybe        as MTM 
import Data.Conduit                     as CDT 
import System.IO                        as IO

stdinS :: Source IO String
stdinS = void . runMaybeT . forever $ do
    (liftIO isEOF) >>= \case
        True  -> mzero
        False -> (lift . yield) =<< (liftIO getLine)

myK :: Sink String IO ()
myK = void . runMaybeT . forever . runMaybeT $ do
    a <- maybe (lift mzero) return =<< (lift . lift $ await)
    b <- if a == "listen"
      then maybe (lift mzero) return =<< (lift . lift $ await)
      else mzero
    liftIO . putStrLn $ "I heard: " ++ b

main :: IO ()
main = do
    stdinS $$ myK 

您将如何更改 myK 以将 ConduitM 置于堆栈顶部?不可否认,在这个特定示例中使用 MaybeT 过于复杂,但在我的实际(更大)管道中,MaybeT 结构比例如更清晰递归。

最佳答案

ConduitM 本身 是一个 monad 转换器,并且查看 Haddock page对于它,我们看到它定义了 MonadStateMonadReader 等的实例。这应该表明,实际上该模式旨在拥有 ConduitM在转换器堆栈的顶部,在这种情况下,您不需要将任何操作提升到其中。

事实上,它甚至为MonadBase定义了一个实例。 ,该类允许您从位于堆栈最底部的 monad 中提升操作(使用 liftBase 函数),因此如果重新排序您的堆栈意味着很难访问 new 底部的东西,MonadBase 为您解决了这个问题。如果你在底部有 IO,这可能不是很有用。

我建议您尝试重新排序您的转换器堆栈,以便尽可能将 ConduitM 放在顶部。

编辑:另一种选择是创建您自己的类 MonadConduit,它定义了广义的 yieldawait 函数,并为 ConduitM 和您在其上使用的所有其他转换器添加实例。我认为这不如尽可能重新排序堆栈优雅。

关于haskell - 管道是否有 `liftIO` 等价物?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33578055/

相关文章:

haskell - 是否可以实现 `(Applicative m) => Applicative (StateT s m)` ?

haskell - 如何组合不同的 Monad Stacks?

haskell - runhaskell 可以从 .ghci 中获取选项吗?

haskell - 使用 Haskell 的 Parsec 解析 float

haskell - react 香蕉 : Alternate buttons events

haskell - 自动将 Either 提升到 exceptT

haskell - 准引号中的 “quasi” 是什么意思?

haskell - 尝试在 Mac(小牛队)上安装 gtk 的 fatal error

haskell - 从 ErrorT 转换到 exceptT

haskell - 结合状态和列表单子(monad)