用另一个 Traversal 镜头扩展一个 Traversal 镜头

Extend one Traversal lens with another Traversal lens

假设我有一个节点,它可以有 children 和兄弟姐妹,我有它们的遍历镜头实现。我如何将它们组合成一个同时遍历 children 和兄弟姐妹的单一镜头?

_children :: Traversal' Node Node
_children = ...

_siblings :: Traversal' Node Node
_siblings = ...

_relatives :: Traversal' Node Node
_relatives = ???

这似乎是一个非常基本的问题,但我找不到任何关于如何"add"从一个遍历到另一个遍历的信息。

这是我使用 wander 函数得到的最接近的值:

_relatives :: Traversal' Node Node
_relatives = wander tra
  where
  tra1 :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
  tra1 = traverseOf _children

  tra2 :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
  tra2 = traverseOf _siblings

  tra :: forall f. Applicative f => (Node -> f Node) -> Node → f Node
  tra g w = lift2 combine fw' fw''
    where
    fw' = tra1 g w

    fw'' = tra2 g w

    combine (Node w') (Node w'') = Node (w' { siblings = w''.siblings })

要是我能去掉最后一行就好了...

combine (Node w') (Node w'') = Node (w' { siblings = w''.siblings })

理想情况下,我的 tra 会像这样(将 tra1 的结果链接到 tra2):

tra :: forall f. Monad f => (Node -> f Node) -> Node -> f Node
tra g w = tra2 g =<< tra1 g w

但我不能那样做,因为 wander 要求 Applicative 约束而不是 Monad。而且我无法链接 Applicative.

的结果

如果我的 Node 实现 Semigroup:

,我也可以通用地执行此操作
tra :: forall f. Applicative f => (Node -> f Node) -> Node -> f Node
tra g w = lift2 append fw' fw''
  where
  fw' = tra1 g w
  fw'' = tra2 g w

但我没有 Semigroup 用于我的真实用例...

难道真的没有通用的方法来合并两次遍历吗?

我真的希望有人能想出更好的方法。如果没有,我会在一段时间后将此答案标记为已接受。

编辑:

事实证明我不是唯一希望这样做的人,而且由于这种转换的 "sequencing" 性质,显然这是不可能的 - 它需要一个 Monad 而我们只有一个 Applicative https://github.com/ekmett/lens/issues/109

将接受这个答案,因为可能没有比 "there is no answer" 更好的答案了。