使用 graphviz 可视化 Haskell 数据树

Visualize Haskell Data Tree with graphviz

我尝试用 Graphviz 可视化 Haskell 树:

import Data.GraphViz.Types as G 

data Animal = Dog String | Cat String
data Stable = Stable [Animal] 

main :: IO ()
main= let myanimals=Stable [Dog "Max",Cat "Cooper"]
    in print $G.printDotGraph myanimals

输出应该是点格式的,类似于:

digraph {
    Stable -> Dog "Max";
    Stable -> Cat "Cooper";
}
   

但是代码会产生一条错误消息:

* Couldn't match expected type `dg0 n0' with actual type `Stable'
* In the first argument of `printDotGraph', namely `myanimals'
  In the second argument of `($)', namely `printDotGraph myanimals'
  In the expression: print $ printDotGraph myanimals

我做错了什么?

您必须将您的数据类型转换为该包可以呈现的图形;它不会为您进行转换。它确实允许转换 fgl graph to its DotGraph type. For that, you can construct a graph with one of the concrete graph types like Data.Graph.Inductive.PatriciaTree using the mkGraph 函数。这是您如何做到这一点的未经测试的草图。具体细节取决于您要生成的图表。 (它可以做得更紧凑,但我试图更明确地说明。)

type NodeLabel = String  -- Just the animal name.
type EdgeLabel = ()      -- No information for now.

graphFromStable :: Stable -> Gr NodeLabel EdgeLabel
graphFromStable (Stable animals) = mkGraph nodes edges
  where

    -- Define the set of nodes in your desired graph.
    nodes :: [LNode NodeLabel]
    nodes = stableNode : animalNodes

    -- Make an edge from the stable node to each animal node.
    edges :: [(Node, Node, EdgeLabel)]
    edges =
      [ (stableId, animalId, ())
      | (animalId, _animalLabel) <- animalNodes
      ]

    -- Define the stable node’s ID and label.
    stableNode :: LNode NodeLabel
    stableNode@(stableId, _stableName) = (0, "Stable")

    -- Give IDs and labels to each animal node.
    animalNodes :: [LNode NodeLabel]
    animalNodes = zip [1..] (map animalLabel animals)

    -- Get a label for an animal node.
    animalLabel :: Animal -> NodeLabel
    animalLabel (Dog name) = name
    animalLabel (Cat name) = name

那么你应该可以在这个函数的结果上使用graphToDot将其转换为DotGraph类型,最后使用printDotGraph.

(其他图形表示之一可能允许您更方便地针对您的用例执行此操作,例如,使用字符串而不是整数作为节点 ID,但我对这些库不太熟悉,无法立即判断。 )

如果您想要更快更脏的东西,另一种方法是将图形打印为一串 Dot 源代码。但我会投资于将这些结构化类型用于任何重要的事情,因为它会给你更多来自类型的指导,并让你使用 FGL 的图形算法来分析和转换你的图形。