我正在设想一个monadic图的实现。我会尽力解释如何在这里构建它。
图表类型应与以下内容同构:
data Graph e v = Graph{ vertices :: [v], edges :: [(e, (v, v))] }
其中e
是边缘类型,v
是顶点类型,我们包括顶点列表和边缘列表以及它们连接的顶点。
我想象的是这种类型的monad实例如下:
instance Monad (Graph e) where
return v = Graph v [] -- | Empty graph with one vertex
m >>= f = {- see below -}
我知道如何实现>>=
基本上采用每个顶点,将其映射到新图形,然后根据原始图形的连接方式相应地重新连接构建每个图形的顶点。
例如,考虑一个函数f
,它接受一个顶点并从它产生两个顶点(K_2
)上的完整图形。然后,如果我们将K_2
本身绑定到f
,我们会得到类似的内容:
A----B
| |
C D
图表A----B
是原始图表,图表A----C
和B----D
分别来自A
和B
。最后,A
和B
需要连接,因为它们是在原始图表中连接的。请注意,A
和B
无需完全相同,但他们需要直接映射到新图表中的某些内容。我为了简单起见省略了一些信息(图表的边缘是什么等),但我注意到的要点是,为了实际作为Monad
实例工作,A
需要直接映射到f A
中的顶点,B
也是如此。通常,原始图中的每个顶点都需要直接映射到f
得到的图形中的图形。
如果我理解正确,这意味着f
must be a retraction for some other morphism g
。如果是,我们可以通过将其结果图中的每个变形顶点连接到其他图形中的变形顶点来清楚地连接图形,从而生成我们想要的类型的新图形。
大多数情况下,这只是我的一个想法,但我真的想在Haskell中有任何方法,要求 f
是一个撤回?有没有办法在语言范围内说明这一点,以便为图形提供Monad
的适当实例,或者要做到这一点,我必须说“如果你的功能,这真的只是一个单子”重新约束是一种收缩?“我怀疑后者,但我只是想检查一下。
或者,我可能会理解一切错误!请随意纠正我或给我一些自己的想法。
答案 0 :(得分:2)
就像评论所说,你可以使用尖头图:
module PointedGraph where
import Control.Arrow (second)
data PointedGraph e v = PointedGraph { hops :: [(e, PointedGraph e v)], center :: v }
deriving (Eq, Show)
instance Monad (PointedGraph e) where
return = PointedGraph []
PointedGraph hs c >>= f = PointedGraph (hs' ++ map (second (>>= f)) hs) c'
where PointedGraph hs' c' = f c
connect :: PointedGraph e v -> e -> PointedGraph e v -> PointedGraph e v
connect g e g' = g { hops = (e,g') : hops g }
k2, ex :: PointedGraph String Int
k2 = connect (return 0) "original" (return 2)
ex = do
n <- k2
connect (return n) "derived" (return $ n + 1)
这样做:
k2: 0 -original-> 2
ex: 0 -original-> 2
| |
derived derived
| |
v v
1 3
请注意,我们没有检查顶点标签的唯一性(需要Eq
约束等),所以我们可以很容易地得到像
k2 >>= const k2:
0 -original-> 0
| |
original original
| |
v v
2 2