I don't see anything like that. ASetter
is defined
type ASetter s t a b = (a -> Identity b) -> s -> Identity t
so it's not powerful enough for the job (and Setter
can't do it either). It turns out, on the other hand, that a Lens
is a bit stronger than necessary. Let's consider, then, how to do it with a Traversal
.
type Traversal s t a b =
forall f. Applicative f => (a -> f b) -> s -> f t
So
Traversal s s a b =
forall f. Applicative f => (a -> f b) -> s -> f s
Which Applicative
do we want? m
seems like the obvious one to try. When we pass the traversal a -> m b
, we get back s -> m s
. Great! As usual for lens
, we'll actually only require the user to provide an ATraversal
, which we can clone.
modifyingM
:: MonadState s m
=> ATraversal s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- cloneTraversal t f s
put s'
That's nice because it only traverses the state once.
Even that is overkill, really. The most natural thing is actually
modifyingM
:: MonadState s m
=> LensLike m s s a b
-> (a -> m b) -> m ()
modifyingM t f = do
s <- get
s' <- t f s
put s'
You can apply that directly to a Traversal
, Lens
, Iso
, or Equality
, or use cloneTraversal
, cloneLens
, cloneIso
, or (in lens-4.18
or later) cloneEquality
to apply it to the monomorphic variants.