简体   繁体   中英

How can I use `over` from Control.Lens but perform a monadic action and collect the results?

The problem is pretty simple. I have a structure that looks something like this

data Foo = Foo [Bar]
data Bar = Boo | Moo Item Int
data Item = Item String Int

and I have a lens for changing the contents of the Item s inside the data structure, such as this

let foos = [Foo [Boo, Moo (Item "bar" 20) 10]]
over (traverse._Foo._Moo._1._Item._1) ("foo" ++) foos

-- which yields [Foo [Boo, Moo (Item "foobar" 20) 10]]

The structure here isn't important, I just wanted to show an example that uses prisms and something deeply nested.

Now the problem is that I need the function passed to over to be String -> IO String , instead of just String -> String . A similar thing to what I'm looking for here is something like mapM , but with lenses. Is it possible to do something like this?

Lens provides the traverseOf function, which is exactly like mapM but takes a lens-like (it takes a traversal, which includes lenses and prims) over which you want to map .

traverseOf :: Functor f => Iso s t a b       -> (a -> f b) -> s -> f t
traverseOf :: Functor f => Lens s t a b      -> (a -> f b) -> s -> f t
traverseOf :: Applicative f => Traversal s t a b -> (a -> f b) -> s -> f t

So for your example, you can just use:

traverseOf (traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos

There is also an operator version of traverseOf , called %%~ .


If you're a bit familar with the representation of lenses inside the lens library, you might notice that traverseOf = id ! So, with this knowledge, you can rewrite the example to just:

(traverse._Foo._Moo._1._Item._1) (... expression of type String -> IO String ...) foos

(You even used traverse which is just mapM to build the traversal! lenses / prims are just like traverse , but more specific.)

But this is just an aside, you might nevertheless want to use traverseOf for clarity.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM