簡體   English   中英

如何壓平IO(IO())?

[英]How to flatten IO (IO ())?

我只是在學習Haskell和monad變換器,我發現自己有一個IO(IO()),我想把它變成IO()。 我確信我做錯了什么,但無法准確指出我迷路的地方。

這是我正在嘗試做的簡化示例。 這是一種實現echo的復雜方式,但它說明了這個問題。

userInput :: Monad m => ReaderT (IO String) m (IO String)
userInput = ask

echo :: Monad m => ReaderT (IO String) m (IO ())
echo = userInput >>= \input ->  -- unwrap ReaderT to get an IO String
         input >>= (\s ->       -- unwrap IO String to get a String
           putStrLn s)          -- print out the String
         & return               -- rewrap into a ReaderT

main :: IO (IO ())              -- How to turn IO (IO ()) to IO ()?
main = runReaderT echo getLine

在我的實際應用程序中,我有一個Spock應用程序向上游服務器發出HTTP請求。 Spock應用程序使用名為SpockCtxT的monad轉換器堆棧,我想將一個ReaderT插入到堆棧中以抽象HTTP請求,以便我可以在我的測試中將其替換為模擬實現。

從根本上說,這個想法是monad變換器堆棧,其中一個變換器為您提供IO無論是HTTP請求還是getLine 我是在考慮這個錯誤還是有辦法做到這一點?

使用join 它有類型簽名

join :: Monad m => m (m a) -> m a

哪個專攻

join :: IO (IO ()) -> IO ()

你可以使用hoogle找到它。 它是一個命令行工具。 我們可以按類型簽名搜索:

hoogle "IO (IO ()) -> IO ()"

Control.Monad join :: Monad m => m (m a) -> m a
Control.Composition (.$) :: Monad m => m (m a) -> m a
RIO join :: Monad m => m (m a) -> m a
Universum.Monad.Reexport join :: Monad m => m (m a) -> m a
Stack.Prelude join :: Monad m => m (m a) -> m a
Relude.Monad.Reexport join :: Monad m => m (m a) -> m a
Intro join :: Monad m => m (m a) -> m a
Hledger.Web.Import join :: Monad m => m (m a) -> m a
Data.Edison.Seq concat :: Sequence s => s (s a) -> s a
Data.Edison.Seq.Defaults concatUsingFoldr :: Sequence s => s (s a) -> s a
-- plus more results not shown, pass --count=20 to see more

它有幾個功能,正是你想要的。

問題的答案是join :: IO (IO ()) -> IO () 但我認為你應該問的問題的答案是liftIO :: IO () -> ReaderT (IO String) IO () 像這樣:

userInput :: MonadIO m => ReaderT (IO String) m String
userInput = ask >>= liftIO -- this liftIO eliminates your need for join

echo :: MonadIO m => ReaderT (IO String) m ()
echo = userInput >>= liftIO . putStrLn -- this liftIO is just so you can use putStrLn in ReaderT

main :: IO ()
main = runReaderT echo getLine

構建返回monadic動作的monadic動作,然后手動組合內部動作,在大多數情況下忽略了monad變換器的全部要點。 不應該有兩層monadic動作,你應該有一個單層,它在內部動作之上有一個外部動作的變換器版本 - 也就是說,而不是使用ReaderT r Foo (IO a)動作,這需要手動綁定ReaderT r Foo層和IO層,你應該使用ReaderT r (FooT IO) a動作,其中只有一個綁定一次處理reader,foo和IO效果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM