首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何扁平化IO (IO ())?

如何扁平化IO (IO ())?
EN

Stack Overflow用户
提问于 2018-12-27 02:41:11
回答 2查看 554关注 0票数 3

我只是在学习Haskell和monad变压器,我发现自己有一个IO (IO ()),我想把它压成IO ()。我肯定我做错了什么,但不能准确地指出我迷路的地方。

下面是一个简单的例子,说明我正在尝试做什么。这是一种复杂的实现echo的方法,但它说明了这个问题。

代码语言:javascript
复制
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

在我的实际应用程序中,我有一个斯波克应用程序,它向上游服务器发出HTTP请求。Spock应用程序使用一个名为SpockCtxT的monad转换器堆栈,我希望在堆栈中插入一个ReaderT来抽象HTTP请求,以便在测试中将其替换为模拟实现。

从根本上讲,这个想法是一个单一的转换器栈,其中一个转换器给您一个IO,不管它是HTTP还是getLine。我是不是想错了,还是有办法这么做?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-12-27 04:13:08

问题的答案是join :: IO (IO ()) -> IO ()。但我认为你应该问的问题的答案是liftIO :: IO () -> ReaderT (IO String) IO ()。如下所示:

代码语言:javascript
复制
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

构建返回一元动作的一元动作,然后手动组合内部动作,在大多数情况下都忽略了单体变压器的全部功能。不应该有两层一元操作,而应该有一个层,它在内部操作之上有外部操作的转换器版本--也就是说,不使用ReaderT r Foo (IO a)操作,因为ReaderT r Foo层和IO层都需要手动绑定,您应该使用ReaderT r (FooT IO) a操作,其中只有一个绑定同时处理读取器、foo和IO效果。

票数 10
EN

Stack Overflow用户

发布于 2018-12-27 02:59:13

使用join。它具有类型签名。

代码语言:javascript
复制
join :: Monad m => m (m a) -> m a

专门为

代码语言:javascript
复制
join :: IO (IO ()) -> IO ()

您可以使用马蹄来查找这个问题。这是一个命令行工具.我们可以按类型搜索签名:

代码语言:javascript
复制
hoogle "IO (IO ()) -> IO ()"

给出

代码语言:javascript
复制
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

它有几个功能就是你想要的。

票数 13
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53939191

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档