Question

I currently have code that looks like this:

do
  x <- use foo
  foo <~ runFoo x

where foo is a Lens to a Foo field and runFoo :: MonadState m => Foo -> m Foo

I think there should be a way to do this operation in one line, but I cannot find it. I think it ought to have a comment like:

(????) :: MonadState s m => Lens' s a -> (a -> m a) -> m a

Questions:

  • Does such a combinator exist? if so what is it?
  • When I run into another question like this, what is the best way to search for it (i.e. Usually I would just type this into Hoogle but I've not had good luck doing that with the lens library)
  • Is this actually a primitive combinator found in Control.Monad? (I will be slightly embarrassed if this is yet another job for the kleisli arrow)
Was it helpful?

Solution

lens doesn't offer such a combinator in a ready-made form. If instead of runFoo you had some g :: a -> a function, you would be able to use (%=), which is to over what use is to view, and write simply foo %= g. Your desired functionality, though, involves interleaving the m effects introduced by runFoo in between the getting and setting, which precludes a solution this straightforward.

OTHER TIPS

The type signature of the function you are looking for is suspiciously close to that of >>=, but with the first argument different.

In particular, it appears as if use foo :: Monad m => m Foo and foo <~ runFoo :: Foo -> m Foo, so you could use bind directly as use foo >>= (\x -> foo <~ runFoo x). There's probably an easier/shorter way, but I don't have the full code to play around with. I'd say just stick with using two lines, and if it's a common enough operation, then define your own combinator for it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top