其他一些人已经简要提到了fgl
Martin Erwig的归纳图和功能图算法,但是可能值得写一个答案,实际上给出归纳表示方法背后的数据类型。
Erwig在他的论文中提出以下类型:
type Node = Int
type Adj b = [(b, Node)]
type Context a b = (Adj b, Node, a, Adj b)
data Graph a b = Empty | Context a b & Graph a b
(中的表示fgl
形式略有不同,并且很好地利用了类型类-但思想本质上是相同的。)
Erwig正在描述一个多图,其中节点和边都有标签,并且所有边都指向其中。A Node
具有某种类型的标签a
;边缘有某种标签b
。甲Context
只是(1)指向标记边缘的列表,以一个特定的节点,(2)所讨论的节点,(3)的节点的标签,和(4)指向标记边缘的列表从该节点。Graph
然后可以将A 归纳为一个Empty
或Context
与&
现有的合并Graph
。
正如Erwig所言,我们不能随意生成Graph
with Empty
和&
,因为我们可能会生成带有Cons
and Nil
构造函数的列表,或者带有Tree
with Leaf
和的列表Branch
。同样,与列表不同(正如其他人提到的那样),不会有任何规范的表示形式Graph
。这些是至关重要的差异。
但是,使该表示如此强大且与列表和树的典型Haskell表示如此相似的原因在于,Graph
这里的数据类型是归纳定义的。归纳定义列表的事实使我们可以如此简洁地在其上进行模式匹配,处理单个元素并递归处理列表的其余部分。同样,Erwig的归纳表示允许我们一次递归地处理一个图Context
。图形的这种表示形式使其很容易定义对图形进行映射的方法(gmap
),以及对图形进行无序折叠的方法(ufold
)。
此页面上的其他评论都很棒。但是,我写这个答案的主要原因是,当我阅读诸如“图形不是代数”之类的短语时,我担心有些读者会不可避免地摆脱(错误的)印象,即没人能找到代表图形的好方法在Haskell中,这种方式允许对它们进行模式匹配,在其上进行映射,对其进行折叠,或者通常做一些我们用来处理列表和树的凉爽,功能性的工作。
fgl
包开发的这一点。