gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 02:16:04 25 4
gpt4 key购买 nike

我正在编写一个越来越大的管道,其中包含嵌套的 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com