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

1

8

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 Items 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?

Govan answered 1/7, 2014 at 16:17 Comment(0)
C
12

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.

Chlorothiazide answered 1/7, 2014 at 16:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.