首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何用镜头表示“`mapM`”和“串联”以连接IO操作的结果?

如何用镜头表示“`mapM`”和“串联”以连接IO操作的结果?
EN

Stack Overflow用户
提问于 2014-07-01 21:16:17
回答 1查看 642关注 0票数 4

我正试图找出一种如何将traverseOf>>=结合起来的方法,以便能够实现以下功能。

普通Haskell中的一个简单例子是这样的,但是在数据结构中使用镜头。

代码语言:javascript
复制
λ> fmap concat $ mapM ((return :: a -> IO a) . const ["he", "he"]) ["foo", "bar", "baz"]
["he","he","he","he","he","he"]

下面是一个长时间的例子说明

代码语言:javascript
复制
data Foo = Foo [Bar] deriving Show
data Bar = Baz | Qux Int [String] deriving Show

makePrisms ''Foo
makePrisms ''Bar

items :: [Foo]
items = [Foo [Baz], Foo [Qux 1 ["hello", "world"], Baz]]

-- Simple replacement with a constant value
constReplace :: [Foo]
constReplace = over (traverse._Foo.traverse._Qux._2.traverse) (const "hehe") items
-- λ> constReplace
-- [Foo [Baz],Foo [Qux 1 ["hehe","hehe"],Baz]]

-- Doing IO in order to fetch the new value. This could be replacing file names
-- with the String contents of the files.
ioReplace :: IO [Foo]
ioReplace = (traverse._Foo.traverse._Qux._2.traverse) (return . const "hehe") items
-- λ> ioReplace
-- [Foo [Baz],Foo [Qux 1 ["hehe","hehe"],Baz]]

-- Replacing a single value with a list and concatenating the results via bind
concatReplace :: [Foo]
concatReplace = over (traverse._Foo.traverse._Qux._2) (>>= const ["he", "he"]) items
-- λ> concatReplace
-- [Foo [Baz],Foo [Qux 1 ["he","he","he","he"],Baz]]

-- Same as the previous example, but the list comes from an IO action
concatIoReplace :: IO [Foo]
concatIoReplace = (traverse._Foo.traverse._Qux._2) (return . (>>= const ["he", "he"])) items
-- λ> concatIoReplace
-- [Foo [Baz],Foo [Qux 1 ["he","he","he","he"],Baz]]

最后一个例子是问题所在,因为我改变了正在应用的函数,从而欺骗了一些人。在concatReplace中,我能够使用>>= (多亏了#haskell-lens频道上的一些乐于助人)来实现concatMap-like功能。但是在我真正的代码中,我拥有的函数是String -> IO [String],它看起来如下所示

代码语言:javascript
复制
correctConcatIo :: IO [Foo]
correctConcatIo = (traverse._Foo.traverse._Qux._2) (>>= (return . const ["he", "he"])) items

但这个例子不再是打字机了。我需要的基本上是将ioReplaceconcatReplace的逻辑组合在一起,这样我就能够将带有String -> IO [String]类型的函数应用到包含[String]的数据结构中。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-07-01 21:37:33

只有在字符串已经在列表中的情况下,才能用字符串替换字符串(考虑尝试将Int重新插入到_Qux._1中),因此必须将函数转换为[String]->IO [String],并使用一些已经演示过的方法替换整个列表:

代码语言:javascript
复制
concatMapM f l = fmap concat (mapM f l)

doIOStuff s = return ['a':s, 'b':s]

concatIO :: IO [Foo]
concatIO = (traverse._Foo.traverse._Qux._2) (concatMapM doIOStuff) items

您甚至可以将该concatMapM组合到末尾,以获得具有LensLike类型的东西,但它不够灵活,无法与大多数透镜组合器一起使用。

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

https://stackoverflow.com/questions/24519389

复制
相关文章

相似问题

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