我很难弄清楚如何在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 票数:7 已采纳

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

  1. 您正在读取数据,这对于一种面向行的语言来说很好。 稍后您将看到Data.ByteStringData.Text替换String以提高效率。 您还将看到Parsec进行解析。 但是,他们可以等待。 及时重温它们。

  2. 你的图表表示没问题。 邻接表是常见且有用的表示形式。

  3. 现在,你真正的伎俩就在这里。 让我们看一下addNodeaddEdge 每个函数都很难用纯函数式语言生成,因为它们想要修改图形...但是我们没有状态。

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

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修改功能链接在一起。

  ask by user677786 translate from so

未解决问题?本站智能推荐: