i'm watching control.lens
introduction video.
makes me wonder why needed setter
type wrap things in functors.
it's (roughly) defined this:
type control.lens.setter s t b = (functor f) => (a -> f a) -> s -> f t
let's have data called point
that's defined this:
data point = point { _x :: int, _y :: int } deriving show
then can write own xlens
this:
type mysetter s t b = (a -> b) -> s -> t xlens :: mysetter point point int int xlens f p = p { _x = f (_x p) }
and can use this:
p = point 100 200 xlens (+1) p -- results in point { _x = 101, _y = 200 }
by using control.lens
, same effect achieved by:
over x (+1) p
where following stands:
x :: functor f => (int -> f int) -> point -> f point on :: setter point point int int -> (int -> int) -> point -> point
so question is, since same effect can achieved in simpler manner, why control.lens
wraps things in functors? looks redundant me, since xlens
same control.lens
's over x
.
just record, can chain lenses in same manner:
data atom = atom { _element :: string, _pos :: point } deriving show poslens :: mysetter atom atom point point poslens f = { _pos = f (_pos a) } = atom "oxygen" p (poslens . xlens) :: (int -> int) -> atom -> atom (poslens . xlens) (+1) -- results in atom "oxygen" (point 101 200)
this wonderful question , require little bit of unpacking.
i want gently correct on 1 point right off bat: type of setter in lens
package of recent versions is
type setter s t b = (a -> identity b) -> s -> identity t
no functor
in sight ... yet.
that not invalidate question however. why isn't type simply
type setter s t b = (a -> b) -> s -> t
for first have talk lens
.
lens
a lens
type allows perform both getter , setter operation. these 2 combined form 1 beautiful functional reference.
a simple pick lens
type is:
type getter s = s -> type setter s t b = (a -> b) -> s -> t type lens s t b = (getter s a, setter s t b)
this type unsatisfying.
- it fails compose
.
, perhaps single best selling point oflens
package. - it rather memory inefficient build lots of tuples, rip them apart later.
- the big one: functions take getters (like
view
) , setters (likeover
) cannot take lenses because types different.
without last problem solved why bother writing library? hate users have think in uml hierarchy of optics, adjusting function calls each time move or down.
the question of moment then: there type can write down lens
such automatically both getter
, setter
? , have transform types of getter
, setter
.
getter
first note
s -> a
equivalentforall r. (a -> r) -> s -> r
. transformation continuation passing style far obvious. might able intuit transformation this: "a function of types -> a
promise givens
can hand mea
. should equivalent promise given function mapsa
r
can hand me function mapss
r
also." maybe? maybe not. there might leap of faith involved here.now define
newtype const r = const r deriving functor
. noteconst r a
samer
, mathematically , @ runtime.now note
type getter s = forall r. (a -> r) -> s -> r
can rewrittentype getter s t b = forall r. (a -> const r b) -> s -> const r t
. though introduced new type variables , mental anguish ourselves type still mathematically identical started out (s -> a
).
setter
define
newtype identity = identity a
. noteidentity a
samea
, mathematically , @ runtime.now note
type setter s t b = (a -> identity b) -> s -> identity t
still identical type started out with.
all together
with paperwork out of way, can unify setters , getters 1 single lens
type?
type setter s t b = (a -> identity b) -> s -> identity t type getter s t b = forall r. (a -> const r b) -> s -> const r t
well haskell , can abstract out choice of identity
or const
quantified variable. the lens wiki says, const
, identity
have in common each functor
. choose sort of point of unification these types:
type lens s t b = forall f. functor f => (a -> f b) -> s -> f t
(there other reasons choose functor
too, such prove laws of functional references using free theorems. handwave little bit here time.) forall f
forall r
. above – lets consumers of type choose how fill variable in. fill in identity
, setter. fill in const a
, getter. choosing small , careful transformations along way able arrive @ point.
caveats
it might important note derivation not original motivation lens
package. derivation wiki page states explains, can start interesting behavior of (.)
functions , tease out optics there. think path carved out little better @ explaining question posed, big question had starting out too. want refer lens on tea, provides yet another derivation.
i think these multiple derivations thing , kind of dipstick healthiness of lens
design. able arrive @ same elegant solution different angles means abstraction robust , well-supported different intuitions , mathematics.
i lied little bit type of setter in recent lens
. it's actually
type setter s t b = forall f. settable f => (a -> f b) -> s -> t b
this example of abstracting higher-order type in optical types provide library user better experience. f
instantiated identity
, there instance settable identity
. every , might want pass setters backwards
function, fixes f
backwards identity
. can categorize paragraph "more information lens
wanted know."