-2
我开始使用镜头,直到现在我一直无法在我正在编写的代码库的具体部分中使用它们。我的目标是通过在现有的节点中添加新节点来更新玫瑰树结构,例如Data.Tree
中的玫瑰树结构。要做到这一点我认为这将是有意义的标识具有唯一ID的每个节点,因此它看起来就像是:在Haskell中使用镜头遍历和添加元素到Data.Tree
type MyTree = Tree Id
type Path = [Id]
addToTree :: MyTree -> MyTree -> Path -> MyTree
addToTree originalTree newNode path = undefined
功能addToTree
必须通过以下ID的路径遍历originalTree
并添加该级别的newNode
,返回整个更新的树。我并没有遇到问题,但是我无法找到合适的镜头来执行此操作。
这就是我有到现在为止:
import Control.Lens
import Data.Tree
import Data.Tree.Lens
addToTree :: MyTree -> Path -> MyTree -> MyTree
addToTree tree path branch = tree & (traversalPath path) . branches %~ (branch:)
traversalPath :: (Foldable t, Applicative f, Contravariant f) => t Id -> (MyTree -> f MyTree) -> MyTree -> f MyTree
traversalPath = foldl (\acc id-> acc . childTraversal id) id
childTraversal :: (Indexable Int p, Applicative f) => Id -> p MyTree (f MyTree) -> MyTree -> f MyTree
childTraversal id = branches . traversed . withId id
withId :: (Choice p, Applicative f) => Id -> Optic' p f MyTree MyTree
withId id = filtered (\x -> rootLabel x == id)
但它未能编译:
• No instance for (Contravariant Identity) arising from a use of ‘traversalPath’ • In the first argument of ‘(.)’, namely ‘(traversalPath path)’ In the first argument of ‘(%~)’, namely ‘(traversalPath path) . branches’ In the second argument of ‘(&)’, namely ‘(traversalPath path) . branches %~ (branch :)’
谢谢!
稍作澄清:是“path”的'originalTree'部分的根? – duplode
在我的伪实现过程中,我没有将它包含在路径中,但它在那里有意义。我会说是的。 – Jesuspc
“逆变”用于获取,您想设置,并且您从不使用'cmap'。从traversalPath中删除'Contravariant'约束。 – Gurkenglas