我正在寫一個增長很大的管道,並帶有嵌套monad變換。將lift
的每個yield
或await
調用到基地conduitM
是一項繁瑣的工作。更不用說每次添加或撤消一層轉換時,我需要在每個可能的位置更改lift
的數量。管道是否有'liftIO`等價物?
我一直在尋找類似的功能liftIO
,但不是提升了IO操作應該解除yield
或await
到基於ConduitM
任意變換單子,但我似乎無法找到一個。有沒有辦法實現這樣的事情?
編輯:響應@ 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 m'是'MonadIO'的一個實例,如果'MonadIO m',那麼你就有'liftIO :: MonadIO m => IO a - > ConduitM i o m a'。 'ConduitM'也有所有MTL類的實例(MonadReader/Writer等),因爲'ConduitM'是一個monad變換器,所以你不必寫'lift ask :: ConduitM io(Reader r)r'(例如),你可以做'ask :: ConduitM io(Reader r)r'。 – user2407038
@ user2407038:謝謝你的回答,但我不太確定我應該怎樣處理'yield'和'await'。 – trVoldemort
你應該做的屈服和等待似乎與解除管道中的IO行爲有什麼關係?也許你應該包括一個你想達到的具體例子。如果你的意思是類似於MonadConduit類(類似於MonadReader/Writer/etc)的類,這個不存在,但是'pipes'解決了這個問題,並且基本上和'Conduit'完全相同(參見[Control.Proxy。 Trans](http://hackage.haskell.org/package/pipes-3.2.0/docs/Control-Proxy-Trans.html)) – user2407038