Haskell - 从文件中读取图形规范

时间:2013-04-16 03:31:18

标签: haskell graph

我正在努力弄清楚如何在Haskell中读取(以及如何表示)图形。

文件的输入类似于

NODES 3
EDGE 1 2
EDGE 1 3
EDGE 2 3

我已经想出如何使用以下方法从文件中获取各行输入:

loadFile :: String -> IO [[String]]
loadFile filename = do 
                contents <- readFile filename
                return $ map words $ lines contents

这给出了输出:

loadFile "input.txt"
[["NODES","3"],["EDGE","1","2"],["EDGE","1","3"],["EDGE","2","3"]]

我真正需要弄清楚的是如何将这个图形数据表示为图形。 我想把它设置为边缘列表:

type Edge = (Int,Int)
type Graph = [Edge]

但后来我不确定如何开始实现我需要的功能,例如addNode,addEdge,getNodes,getEdges。

任何帮助或指向我正确的方向都会很棒!注意:我不能使用任何已经开发的图形模块。

所以,对于tl; dr版本:

  1. 我在数据中读取最好的方法吗?
  2. 我应该如何在haskell中表示这些数据?
  3. 如果我使用上面概述的数据结构,我将如何实现其中一个功能。

1 个答案:

答案 0 :(得分:7)

这里有很多有趣的问题。让我攻击他们。

  1. 您正在阅读数据,这对于面向行的语言来说非常合适。稍后,您会看到Data.ByteStringData.Text替换String以提高效率。您还会看到Parsec进行解析。但是,他们可以等待。及时重访。

  2. 您的图表表示很好。邻接列表是一种常见且有用的表示。

  3. 现在,真正的伎俩就在这里。我们来看看addNodeaddEdge。每个都是一个有点挑战性的函数,用纯函数式语言生成,因为他们想修改一个图...但我们没有状态。

  4. 修改无状态最重要的方法是变异。因此,您正在寻找的功能是

    addNode :: Node -> Graph -> Graph
    

    返回的Graph与输入Graph相同,只有一条边。你应该立即注意到这里有什么问题---邻接列表假设没有孤立节点。我们不能只在图表中添加一个节点。

    有两种解决方案。一,我们可以将节点“链接”到图形中(伪装真的是addEdge)或两个我们可以扩展图形表示以包括孤立节点。我们来做(2)。

    data Graph = Graph [Edge] [Int] -- orphans
    

    现在让我们实现添加边缘。假设您可以有重复的边,向邻接列表添加边很容易,只需附加

    addEdge0 :: Edge -> Graph -> Graph
    addEdge0 e (Graph adj orph) = Graph (e:adj) orph
    

    但这还不够好 - 我们希望我们的孤儿列表只包含真正的孤立节点。我们会过滤它。

    addEdge :: Edge -> Graph -> Graph
    addEdge (n1,n2) (Graph adj orph) = 
      Graph ((n1,n2):adj) (filter (/=n1) . filter (/=n2) $ orph)
    

    getEdges是微不足道的,因为我们已经存储了边缘列表

    getEdges :: Graph -> [Edge]
    getEdges (Graph edges _) = edges
    

    getNodes只需要将邻接列表中的所有节点附加到孤立列表。我们可以使用Data.List.nub来获取唯一的节点。

    getNodes :: Graph -> [Int]
    getNotes (Graph adj orph) = nub (orph ++ adjNodes adj) where
      adjNodes [] = []
      adjNodes ((n1,n2):rest) = n1 : n2 : adjNodes rest
    

    希望这些能为您提供一些如何用功能语言思考的指示。你会花些时间去深入了解它们是如何工作的,但我在这里介绍了大量有趣的概念。

    此处的后续步骤可能包括尝试使用State monad重新捕获命令状态修改并将这些Graph链接在一起修改函数。