Control.Lens.Tuple defines lenses to access elements of tuples. For example
class Field3 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-- | Access the 3rd field of a tuple.
_3 :: Lens s t a b
-- >>> (1,2,3)^._3
-- 3
--
-- >>> _3 .~ "hello" $ (1,2,3)
-- (1,2,"hello")
The setter _3 .~
returns a tuple with the third element changed, to a different type in this example.
For class Field3
there's instances defined for tuples with three or more elements. Not for pairs/two-ples, because what would a getter get?
But if a setter can change the type of the nth element, why couldn't it change the type to a different arity of tuple?
-- >>> _3 .~ "hello" $ (1,2)
-- (1,2,"hello")
That is, a setter _3 .~
setting the third element by extending a two-ple.
instance Field3 (a,b) (a,b,c') Dummy c' where
_3 k ~(a,b) = k undefined <&> \c' -> (a,b,c')
In which Dummy
and undefined
is some place-holder type and value for the non-existent third element of the incoming two-ple.
After extending to arity 3, lens _3
works as usual; also lenses _1, _2
obey the lens laws throughout.
Q1. Will this work for a setter?
(of course it won't for an updater/over
)
Q2. If so, is there some way to make it ill-typed to try view
ing the non-existent 3rd element?
Q3. If a setter won't work, could there be an extend
operator that will achieve the effect? (Presumably using a different functor.)
Perhaps the instance could be this
instance Field3 (a,b) (a,b,c') (a,b) c' where
_3 k ~(a,b) = k (a,b) <&> \c' -> (a,b,c')
Such that view
would return a weirdly typed result, and over
could potentially build the third element from the first two.
_3 .~ "hello" $ (1,2)
was accepted and produced the result I wanted. But the instance wasn't accepted: inconsistent with the proper instance, for FunDept a -> s
-- which is quite correct. I just suppressed that FunDep on the class. - AntC(a, b) -> c -> (a, b, c)
, what is the rest of the lens infrastructure getting you that_3' = uncurry (,,)
doesn't? Genericity of some sort? - user11228628_3'
is not that. I see no Functor. - AntCFunctor
; itsFunctor
isIdentity
. If you have a van Laarhoven lensforall f. Functor f => ((a, b) -> f (a, b, c)) -> s -> f t
, you should be able to compose that withc -> (a, b) -> Identity (a, b, c)
to get a setter in the style you want for your larger structure. That's the beauty of van Laarhoven lenses; you can do an awful lot with plain old composition. - user11228628set _3 "hello" (1, 2)
gives(1,2,"hello")
, and the type of_3
has a Functor required in its constraints. Using your def'nset _3' "hello" (1,2)
is ill-typed, and the type of_3'
doesn't mention Functor.set
would introduce theIdentity
Functor. - AntC