I can create an IndexedTraversal
for lists with a constant index like so:
constIndexedList :: i -> Lens.AnIndexedTraversal i [a] [b] a b
constIndexedList _ _ [] = pure []
constIndexedList index f (x:xs) = (:) <$> Lens.indexed f index x <*> constListIndex index f xs
I'd rather create it by composing two simpler lens:
constIndex :: i -> Lens.AnIndexedLens i a b a b
constIndex index f = Lens.indexed f index
constIndexedList :: i -> Lens.AnIndexedTraversal i [a] [b] a b
constIndexedList index = Lens.cloneLens (constIndex index) <. traverse
However this fails to type-check, and the type errors from lens
are not ones that I easily understand:
• Couldn't match type ‘Lens.Indexed
i (t0 a) (Lens.Bazaar (Lens.Indexed i) a b (t0 b))’
with ‘[a] -> Lens.Bazaar (Lens.Indexed i) a b [b]’
Expected type: Lens.Indexed
i (t0 a) (Lens.Bazaar (Lens.Indexed i) a b (t0 b))
-> [a] -> Lens.Bazaar (Lens.Indexed i) a b [b]
Actual type: ([a] -> Lens.Bazaar (Lens.Indexed i) a b [b])
-> [a] -> Lens.Bazaar (Lens.Indexed i) a b [b]
• In the first argument of ‘(<.)’, namely
‘Lens.cloneLens (constIndex index)’
In the expression: Lens.cloneLens (constIndex index) <. traverse
Why can't I compose indexed lens like so?
I ended up finding a different modular way to do it (Lens.reindexed (const index) Lens.traversed
, but I still wonder why the method mentioned above doesn't work..
(<.)
expects an indexed optic on its left, but cloneLens
gives it an unindexed lens.
One partial fix is to use Lens.cloneIndexedLens
instead of cloneLens
.
However, A_
/An_
variants of optics (AnIndexedLens
) are meant to be argument types, not result types, which can use regular optics (IndexedLens
). With that, cloneIndexedLens
becomes unnecessary.
constIndex :: i -> Lens.IndexedLens i a b a b
constIndex i f = Lens.indexed f i
constIndexedList :: i -> Lens.IndexedTraversal i [a] [b] a b
constIndexedList i = constIndex i <. traverse
Monomorphic inputs and polymorphic outputs improve composability.
IndexedLens
is a polymorphic type (notice the forall
keyword in the type definition).
type IndexedLens i s t a b = forall f p. (Indexable i p, Functor f) => p a (f b) -> s -> f t
AnIndexedLens
is monomorphic.
type AnIndexedLens i s t a b = Optical (Indexed i) (->) (Pretext (Indexed i) a b) s t a b
Every IndexedLens
is AnIndexedLens
, but the conversion the other way must go through an explicit cloneIndexedLens
.