Haskell中元组的递归定义

Haskell中元组的递归定义,haskell,tuples,Haskell,Tuples,我正在处理图形,并创建了名为vertex的自定义类型 type Vertex = (Int, [Vertex]) 此类型是一对,它接受Int,Int是特定顶点的索引号,而[顶点]是与此顶点相邻的顶点列表 然后我创建了一个图表的邻接列表。不过我遇到了这个问题。如何定义此给定顶点类型的相邻顶点列表 我们有一个有两个顶点的图。让我们称它们为1和2。他们之间有一条边。因此,顶点1与顶点2相邻,反之亦然。 现在,我的邻接列表如下所示: adjacencyList :: [Vertex] adjacenc

我正在处理图形,并创建了名为vertex的自定义类型

type Vertex = (Int, [Vertex])
此类型是一对,它接受
Int
,Int是特定顶点的索引号,而
[顶点]
是与此顶点相邻的顶点列表

然后我创建了一个图表的邻接列表。不过我遇到了这个问题。如何定义此给定顶点类型的相邻顶点列表

我们有一个有两个顶点的图。让我们称它们为12。他们之间有一条边。因此,顶点1与顶点2相邻,反之亦然。 现在,我的邻接列表如下所示:

adjacencyList :: [Vertex]
adjacencyList = [ (1, [ (2, [ (1, [ (2, [ (1, …) ]) ]) ]) ])
                , here would go the vertex 2 ]
如你所见,问题是我的顶点类型的递归定义-顶点1有相邻顶点2有相邻顶点1有相邻顶点2有相邻顶点1等。这个定义对我来说似乎是无限的

在C++等命令式语言中,我将用指针来解决这个问题。
但是在哈斯克尔,我怎样才能克服这个问题呢?

这就是为什么懒惰很方便的原因。你可以这么做

adjacencyList :: [Vertex]
adjacencyList = [a, b]
    where a = (1, [b])
          b = (2, [a])

如果你来自C++世界,这个代码可能看起来很神秘。但是,它实际上并没有比C++中的相互递归函数更奇怪。(事实上,想法几乎是一样的。)

这就是为什么懒惰很方便。你可以这么做

adjacencyList :: [Vertex]
adjacencyList = [a, b]
    where a = (1, [b])
          b = (2, [a])

如果你来自C++世界,这个代码可能看起来很神秘。但是,它实际上并没有比C++中的相互递归函数更奇怪。(事实上,这个想法几乎是一样的。)

我觉得奇怪的是,每个顶点都应该负责了解它的邻居。这种样式可能适用于C++或其他使用引用相等的语言,但在Haskell中确实很难。 请尝试按以下方式对图形建模:

import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)

type Vertex = Int
type Graph = Map Vertex [Vertex] -- each vertex mapped to its 'out-neighbors'
那么你就不需要建立那些复杂的邻接列表了。获取任意顶点的邻域很简单:

neighbors :: Vertex -> Graph -> [Vertex]
neighbors v g = fromMaybe [] (Map.lookup v g)
关键是标记为
1
的每个
顶点
都是相同的
顶点
,无论它在内存中是否是相同的对象

为了添加连接,我们可以使用
Data.Map
with list append中的
insertWith
函数:

connect :: Vertex -> [Vertex] -> Graph -> Graph
connect = Map.insertWith (++)
当然,我们需要能够创建一个空图:

empty :: Graph
empty = Map.empty
请记住,这是针对有向图的。无向图需要额外注意以保持其不变量。此外,对相邻顶点使用列表意味着我们可以从一个顶点到另一个顶点有多条边。我们可以使用集合来消除这种行为


我希望这能有所帮助。

我觉得奇怪的是,每个顶点都应该负责了解它的邻居。这种样式可能适用于C++或其他使用引用相等的语言,但在Haskell中确实很难。 请尝试按以下方式对图形建模:

import Data.Map (Map)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)

type Vertex = Int
type Graph = Map Vertex [Vertex] -- each vertex mapped to its 'out-neighbors'
那么你就不需要建立那些复杂的邻接列表了。获取任意顶点的邻域很简单:

neighbors :: Vertex -> Graph -> [Vertex]
neighbors v g = fromMaybe [] (Map.lookup v g)
关键是标记为
1
的每个
顶点
都是相同的
顶点
,无论它在内存中是否是相同的对象

为了添加连接,我们可以使用
Data.Map
with list append中的
insertWith
函数:

connect :: Vertex -> [Vertex] -> Graph -> Graph
connect = Map.insertWith (++)
当然,我们需要能够创建一个空图:

empty :: Graph
empty = Map.empty
请记住,这是针对有向图的。无向图需要额外注意以保持其不变量。此外,对相邻顶点使用列表意味着我们可以从一个顶点到另一个顶点有多条边。我们可以使用集合来消除这种行为


我希望这会有所帮助。

顺便说一句,由于类型安全,通常不鼓励使用元组定义这样的类型。最好做
data Vertex=Vertex Int[Vertex]
。我仍然不知道什么时候使用
type
,什么时候使用
data
。我把自定义类型理解为已经存在的类型的“同义词”。顺便说一下,出于类型安全考虑,通常不鼓励使用元组定义这样的类型。最好做
data Vertex=Vertex Int[Vertex]
。我仍然不知道什么时候使用
type
,什么时候使用
data
。我把自定义类型理解为现有类型的“同义词”。另外,如果我想事先用未知数量的顶点动态创建
adjacencyList
该怎么办?@Superian007如果你想这样做,这实际上取决于你从什么样的数据开始。我有一个代表游戏板的列表。在这个游戏板上有黑色和白色的石头,它们都是图形。每种颜色都有自己的图形。所以黑石头有它自己的邻接列表,白石头有它自己的邻接列表。如果我想事先用未知数量的顶点动态创建
邻接列表
,该怎么办?@Superian007如果你想这样做,这真的取决于你从什么样的数据开始。我有一个代表游戏板的列表。在这个游戏板上有黑色和白色的石头,它们都是图形。每种颜色都有自己的图形。所以黑石头有它自己的邻接列表,白石头有它自己的邻接列表。