Search code examples
haskelltraversalhaskell-lens

Compose two Traversals, with read-only access to the middle layer


I'd like to compose two traversals and then traverse the composition with something that also depends on the "middle" layer.

I think that would mean making an IndexedTraversal from the two Traversals:

rememberMidpoint :: Traversal' s a -> Traversal' a b -> IndexedTraversal' a s b

Maybe the question can be simplified further to

remember :: Traversal' s a -> IndexedTraversal' s a a

or

remember :: Traversal' s a -> IndexedTraversal' a s a

?

So my questions are:

  • Am I correct in wanting to use IndexedTraversal for this?
  • If yes, how would I implement either rememberMidpoint, or one of the two remember functions + a way of composing their result with a non-indexed Traversal?

Solution

  • @phadej helped me out over on #haskell-lens, pointing me towards selfIndex:

    Use a value itself as its own index. This is essentially an indexed version of id.

    Together with the combinator <. to compose an indexed and a non-indexed traversal, we get:

    rememberMidpoint :: Traversal' s a -> Traversal' a b -> IndexedTraversal' a s b
    rememberMidpoint outer inner = outer . selfIndex <. inner
    

    And to address @András Kovács's point in the comment:

    According to docs, your intended IndexedTraversal is not legal, as the a index changes if you modify an innermost b.

    I don't believe this to be true: if I understand selfIndex right, the a in the index will stay the the "original" a, not become the one with the modified b inside.