Yes! The first thing to note is that something
must have type Setter
(and, without loss of generality, Setter'
). As for what type let's use holes.
maybeTContents :: Setter' (MaybeT m a) a
maybeTContents =
_Wrapped . _ . _Just
GHC tells us it wants type Settable f => (Maybe a -> f (Maybe a)) -> (m (Maybe a) -> f (m (Maybe a))
for the hole.
With a trip to Hackage we recognize this type as Setter' (m (Maybe a)) (Maybe a)
. So, fixing u ~ Maybe a
, we can rephrase the question more generally: does a setter exist that unifies with both Setter' [u] u
exist and Setter' (Reader u) u
?
But, as both []
and Reader
have functor instances we can turn to an absolute classic of a setter mapped
, the setter heard around the world. mapped
has type mapped :: Functor f => Setter (f a) (f b) a b
– it turns out when you have a functor instance available that mapped = sets fmap
is the value that obeys all the setter laws.
We can see this in action here:
% stack ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
Ok, modules loaded: none.
λ> import Control.Lens
λ> import Control.Monad.Trans.Maybe
λ> import Control.Monad.Trans.Reader
λ> MaybeT [Just 1, Nothing, Just 2, Nothing, Just 3] & _Wrapped . mapped . _Just .~ 100
MaybeT [Just 100,Nothing,Just 100,Nothing,Just 100]
λ> data A = A
λ> data B = B
λ> :t MaybeT (ReaderT (\r -> Identity (Just A)))
MaybeT (ReaderT (\r -> Identity (Just A)))
:: MaybeT (ReaderT r Identity) A
λ> :t MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
:: MaybeT (ReaderT r Identity) B
As there was no Show
instance for ReaderT
the best I could do to illustrate that the setter worked was to generate two brand-spankin'-new types A
and B
.
This question is great I think because it gets at the heart of the motivation behind the lens
package. Given fmapDefault
from the Traversable
world, you can fix the traversable to be Identity
to write over
. You can then write the inverse of over
, sets
, such that over . sets = id
and sets . over = id
. We are then forced to conclude that mapped = sets fmap
is a natural setter that obeys the kind of laws we want for setters, one of the most important being that mapped . mapped . mapped
composes with (.)
. The rest of lens
soon follows.