Haskell 如何静态检查图的有效性?

Haskell 如何静态检查图的有效性?,haskell,Haskell,考虑下面的代码 newtype NodeAT = NodeAT String deriving (Show,Read,Eq,Ord) newtype NodeBT = NodeBT String deriving (Show,Read,Eq,Ord) newtype NodeCT = NodeCT String deriving (Show,Read,Eq,Ord) newtype NodeDT = NodeDT String deriving (Show,Read,Eq,Ord) nodeA

考虑下面的代码

newtype NodeAT = NodeAT String deriving (Show,Read,Eq,Ord)
newtype NodeBT = NodeBT String deriving (Show,Read,Eq,Ord)
newtype NodeCT = NodeCT String deriving (Show,Read,Eq,Ord)
newtype NodeDT = NodeDT String deriving (Show,Read,Eq,Ord)

nodeA = NodeAT "nodeA" 
nodeB = NodeBT "nodeB"
nodeC = NodeCT "nodeC"
nodeD = NodeDT "nodeD"


data Graph n m = Graph
 { vertices :: n
  , edges :: m
 }

graph1 = Graph  (nodeA,nodeB,nodeC,nodeD)  ((nodeA,nodeC),(nodeB,nodeC),(nodeA, nodeC))
是否可以使用类型系统检查边对是否是属于顶点元组的节点实例? 这将通过建筑来实现

graph2 = Graph (nodeA, nodeB) (nodeA, nodeC)

非法且在编译时失败

不确定它是否适合您的需要,但是您可以通过一些类型级别的编程来实现它

当然,还需要一些扩展:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
下面是一个封闭类型族,用于测试某个类型是否是类型级别的类型列表的成员:

type family Elem a as :: Bool where
  Elem a '[] = False
  Elem a (a : as) = True
  Elem a (b : as) = Elem a as
现在,让我们定义从给定顶点类型列表中绘制顶点的顶点和边的类型:

data Vertex :: [*] -> * where
  V :: Elem a as ~ True => a -> Vertex as

type Edge as = (Vertex as, Vertex as)
data NodeA = NodeA
data NodeB = NodeB
data NodeC = NodeC
然后,我们可以定义一类图,其中顶点存储在其类型中,边存储在数据构造函数中:

data Graph :: [*] -> * where
  G :: [Edge as] -> Graph as
以下是一些顶点类型:

data Vertex :: [*] -> * where
  V :: Elem a as ~ True => a -> Vertex as

type Edge as = (Vertex as, Vertex as)
data NodeA = NodeA
data NodeB = NodeB
data NodeC = NodeC
因此,以下图表类型正确:

graph1 :: Graph [NodeA, NodeB]
graph1 = G [(V NodeA, V NodeB)]
但以下情况并非如此:

graph2 :: Graph [NodeA, NodeB]
graph2 = G [(V NodeA, V NodeC)]
它失败于:

  error:
    • Couldn't match type ‘'False’ with ‘'True’
        arising from a use of ‘V’
    • In the expression: V NodeC
      In the expression: (V NodeA, V NodeC)
      In the first argument of ‘G’, namely ‘[(V NodeA, V NodeC)]’

我认为使用异构列表而不是元组是可行的,但我认为这样做没有任何意义。图形通常是动态的,因此顶点/边必须具有相同的类型,并且您可以直接从边获取顶点,因此不需要同时存储它们。这太复杂了,无法实现。我猜原则上可以使用一些gadt、单例和相关技术来静态地执行此操作,但这并不是完全自动的。在构造过程中,用户需要提供不变量的证明——在某些情况下(例如,当只涉及文本时),这可能是自动的,但不是全部。