我的问题涉及将树转换为其功能图形库表示形式的明显笨拙,这需要显式引用节点名称才能插入更多节点/边。
具体来说,我递归地构建了一棵玫瑰树(目前是 a Data.Tree.Tree a
from containers
),并希望将其转换为 aGr a ()
以针对它调用各种函数。为此,可以首先遍历树(使用供应单子或 FGL 的状态单子类型之一,如 NodeMapM)并用标识符标记每个节点:
{-# LANGUAGE TupleSections #-}
import Control.Monad.Supply
import Data.Graph.Inductive
import Data.Tree
tagTree :: Tree a -> Supply Int (Tree (a,Int))
tagTree (Node n xs) = do
xs' <- sequence (map tagTree xs)
s <- supply
return $ Node (n,s) xs'
然后evalSupply (tagTree tree) [1..]
,然后使用类似的东西
taggedTreeToGraph :: Tree (a,Int) -> Gr a ()
taggedTreeToGraph (Node (n,i) xs) =
([],i,n,map (((),) . snd . rootLabel) xs)
& foldr graphUnion empty (map taggedTreeToGraph xs)
where
graphUnion = undefined -- see 'mergeTwoGraphs' in package 'gbu'
当然,这两个阶段可以合并。
那么,这是进行这种转换的好方法吗?或者是否有一种我遗漏的更简单的方法,或者我应该使用将(希望非常通用的)树状数据结构转换为 FGL 树的抽象?
编辑:我想这个问题的重点是我的原始解析器只有四行长,并且使用了非常简单的组合器,例如liftA (flip Node [])
,但是要更改返回的表示似乎需要上面的大代码,这很奇怪。
(我很乐意Gr a ()
直接从解析器(使用 Parsec 的简单应用解析器)和 monad 转换器生成一个,前提是它需要对解析器进行微创更改。)