用另一个 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" 更好的答案了。
假设我有一个节点,它可以有 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" 更好的答案了。