将树转换为功能图库树的优雅方法?

时间:2012-11-13 05:25:46

标签: haskell graph

我的问题涉及将树转换为Functional Graph Library表示的明显尴尬,这需要显式引用节点名称以插入更多节点/边。

具体来说,我递归地构建了一个玫瑰树(目前来自Data.Tree.Tree a的{​​{1}}),并希望将其转换为containers以针对它调用各种函数。要做到这一点,可以先走树(使用供应monad或其中一个FGL的状态monad类型,如NodeMapM),并用标识符标记每个节点:

Gr a ()

然后{-# 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..]

当然,这两个阶段可以结合起来。

那么,这是进行此转换的好方法吗?或者是否有一种我想要的更简单的方法,或者我应该使用将(希望非常通用的)树状数据结构转换为FGL树的抽象方法?

编辑:我想这个问题的重点在于我的原始解析器只有四行,并且使用非常简单的组合器,如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' ,但是更改返回的表示看似需要上面的大代码,这很奇怪

(我很乐意直接从解析器(使用Parsec的简单应用解析器)和monad变换器生成liftA (flip Node []),前提是它需要对解析器进行微创更改。)

1 个答案:

答案 0 :(得分:3)

您可以使用Writer收集节点列表和要传递给mkGraph的边缘列表。使用Writer列表效率不高,因此我使用DList代替,并在结尾处转换回列表。

import Data.Tree
import Data.Graph.Inductive
import Data.DList (singleton, fromList, toList)
import Control.Monad.RWS
import Control.Arrow

treeToGraph :: Tree a -> Gr a ()
treeToGraph t = uncurry mkGraph . (toList *** toList) . snd $ evalRWS (go t) () [1..]
  where go (Node a ns) = do
          i <- state $ head &&& tail
          es <- forM ns $ go >=> \j -> return (i, j, ())
          tell (singleton (i, a), fromList es)
          return i