Это самое близкое, что у меня есть, используя функцию 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
для моего реального варианта использования ...
Неужели нет универсального c способа объединить два обхода?
Я действительно надеюсь, что кто-то может придумать лучший подход. Если нет, я отмечу этот ответ как принятый через некоторое время.
РЕДАКТИРОВАТЬ:
Оказывается, я не единственный, кто хочет это сделать, и по-видимому, это невозможно из-за «последовательности» природы такого преобразования - для этого требуется монада, в то время как у нас есть только аппликативный https://github.com/ekmett/lens/issues/109
Собираюсь принять этот ответ, поскольку, вероятно, нет лучшего ответ, чем "нет ответа".