Reputation: 648
I am looking for a function with type similar to:
Monad m => (a, b) -> (b -> m c) -> m (a, c)
It appears to me as some combination of bind (>>=
) and a lens operation.
I am aware that I can solve this with a pattern match after a bind, but my gut tells me there is a "simpler" way to write this by leveraging lenses.
Is there any such operation?
Upvotes: 5
Views: 273
Reputation: 48631
This is definitely lensy. The monad is actually just a bit of a distraction because all you need is a functor:
changesecond (a, b) f = fmap (a,) (f b)
I'm pretty sure the _2
lens can be made to do your bidding with a basic lens thing like maybe over
but I'm not too familiar with the library yet.
No combinator is really needed. You can write
changesecond pair f = _2 f pair
You should be able to work this out from the general definition of the Lens
type.
This simple example demonstrates the main theme of Van Laarhoven lens construction:
fmap
to restore the contexts to the results.Ed Kmett's lens
library elaborates on this theme in various ways. Sometimes it strengthens the functor constraint. Sometimes it generalizes the function to a profunctor. In the case of Equality
, it removes the functor constraint. It just turns out that the same basic type shape can express a lot of different ideas.
Upvotes: 8
Reputation: 34398
Your function is just forM = flip mapM
, or for = flip traverse
if you relax the Monad
constraint to Applicative
. The Functor
being traversed is (,) a
.
Prelude> let foo :: Applicative f => (a, b) -> (b -> f c) -> f (a, c); foo p k = traverse k p
Prelude> :t foo
foo :: Applicative f => (a, b) -> (b -> f c) -> f (a, c)
Prelude> foo (1,2) (\x -> [x,2*x])
[(1,2),(1,4)]
(Also, as dfeuer points out, you don't even need Applicative
in this specific case.)
Upvotes: 6