【发布时间】:2018-12-27 02:41:11
【问题描述】:
我刚刚学习 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 请求,以便我可以在测试中将其换成模拟实现。
从根本上说,这个想法是一个单子转换器堆栈,其中一个转换器为您提供IO,无论是 HTTP 请求还是getLine。我是在错误地思考这个问题还是有什么办法可以做到这一点?
【问题讨论】:
-
使用
join进行展平。 -
IO (IO ()) -> IO ()是来自 Control.Monad 的join -
旁注:当库导出具有
IO (IO ())之类类型的内容时,它们通常不希望您使用join,而是使用layeredAction >>= \inner -> somethingElse >> inner之类的东西
标签: unit-testing haskell monads monad-transformers