Closed pthariensflame closed 11 years ago
One particular use for Replacer
where Setter
is unusable is with existential data constructors, especially those with multiple fields. Then it might not make sense to map over those values; you could only replace them blindly.
The problem with both of the Replacer
variants is that they don't fit the composability model that everything else does. -- You can't compose them.
I mentioned them in my 'Mirrored Lenses' post on comonad.com. (This is what I originally called a Setter
actually, back when I called what I now call a Setter
a Modifier
)
I dropped them from the system because of the lack of composability.
Since the rank 3 type basically means you wind up wallowing in type signatures, the lack of composability means you don't get to mix them well with other lens types, and the fact that they generally lack laws, I'm not in a hurry to put them back into the hierarchy.
Closing this out as wontfix for now. I might be convinced to re-open it, but the lack of composability, and violation of all of the laws that I've tried to preserve everywhere else leads me to believe these don't bring enough to the table to warrant the explanation of their role, and the type inference or explicit conversion headaches they introduce elsewhere.
For those, who will read this like me. For setting-only operation you can just use Setter s t () b
(it's actually isomorphic to b -> s -> t
, though definitions of Replacer
above are not -- we should use unit type instead of Void
). So
type Replacer s t b = Setter s t () b
replacer :: (b -> s -> t) -> Replacer s t b
replacer h fb = setting (h . ($ ())) fb
-- and standard 'set' operation works fine with it
You can write that down, but it doesn't compose or comply with the laws presented in the original Mirrored Lenses post. Ultimately, the a
and the b
should be related by the same substitution that relate s
and t
, in your Replacer, they are unrelated.
The lens library doesn't preclude you from using such a beast, but it is not a lawful optic, and you have to reason case-by-case, combinator-by-combinator, to see if it does what you want as you go.
Your mileage may vary. Caveat emptor. Here be dragons, etc.
Setter
s are capable of replacing the target value(s) because they are capable of modifying the target value(s). Modification always allows replacement as a special case (viaconst
and its ilk), but you cannot generate modification from solely replacement (if you have both replacement and retrieval, you can, but then you just end up with aTraversal
).This seems to hint at a supertype of
Setter
:Replacer
(plusIndexed
and/orSimple
variants, of course). Essentially:Getter a c
is isomorphic toa -> c
Setter a b c d
is isomorphic to(c -> d) -> a -> b
Replacer a b d
is isomorphic tod -> a -> b
I've come up with a couple of encodings for
Replacer
that try to fit within the van Laarhoven model, and I'd like to generate some discussion of this. It's not critical to me, but it is an interesting hole in the current design space.type Replacer a b d = forall f. (Settable f) => (forall c. c -> f d) -> a -> f b
type Replacer a b d = forall f. (Settable f) => (Void -> f d) -> a -> f b