我正在尝试制作一个简单的图形结构,我写了以下内容。但温室气体引起了错误,我堆积在那里。这是我第一次制作自己的类型类,所以也许我做的事情非常糟糕。有人可以解释什么是错的吗?
我发现了类似的问题,但我不认为它适用于我的情况: Error binding type variables in instance of typeclass
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
data (Node n) => SimpleLink n =
SimpleLink
{ simpleLinkNode :: n
} deriving (Show, Read, Eq)
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
data (Link l) => SimpleNode l =
SimpleNode
{ simpleNodeLinks :: [l]
} deriving (Show, Read, Eq)
instance (Link l) => Node (SimpleNode l) where
links = simpleNodeLinks
这是我收到的错误消息:
***.hs:13:10:Could not deduce (n ~ n1)
from the context (Node n)
bound by the instance declaration
at ***.hs:12:10-40
or from (Node n1)
bound by the type signature for
node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3-23
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
Expected type: SimpleLink n -> n1
Actual type: SimpleLink n -> n
In the expression: simpleLinkNode
In an equation for `node': node = simpleLinkNode
***.hs:21:11:Could not deduce (l ~ l1)
from the context (Link l)
bound by the instance declaration
at ***.hs:20:10-40
or from (Link l1)
bound by the type signature for
links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3-25
`l' is a rigid type variable bound by
the instance declaration
at ***.hs:20:16
`l1' is a rigid type variable bound by
the type signature for links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3
Expected type: SimpleNode l -> [l1]
Actual type: SimpleNode l -> [l]
In the expression: simpleNodeLinks
In an equation for `links': links = simpleNodeLinks
我尝试了一些Daniel's suggestions。 但是我无法让它们发挥作用。
得到:“`n'不适用于足够的类型参数”
class Link l n where
node :: Node n l => l n -> n l
class Node n l where
links :: Link l n => n l -> [l n]
得到:“在类声明中循环(通过超类)”
class (Node n) => Link l n where
node :: l -> n
class (Link l) => Node n l where
links :: n -> [l]
得到:“在类声明中循环(通过超类)”
class (Node n) => Link l n | l -> n where
node :: l -> n
class (Link l) => Node n l | n -> l where
links :: n -> [l]
我想要实现的是一个有向无环图结构,如下所示(更具体地说,是一个Factor graph)。
有两种节点(白色圆圈和红色方块),它们只连接到不同类型的节点,这意味着有两种链接。
我想要不同版本的节点和连接数据(数组)的链接。我也想要“vanilla”DAG,它只有一种类型的节点和链接。但是为了遍历它们,我只想要一个接口来做到这一点。
答案 0 :(得分:6)
类方法的签名
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
说“只要<{1}} resp。{{{ {1}}“,但实现表明只能生成一种特定类型的值。
它与OOP中的接口有根本的不同,OOP中的实现决定了类型,调用者必须接受它,调用者在这里决定。
您正在遇到构造函数类尝试的问题。您的类有两个参数,node
种类links
和Link
种类Node
。 l
的参数类型必须都是kl
,类型的种类。因此,n
要成为kn
的良好论证,(->)
必须是一个类型构造函数,它接受类*
的参数并创建类型{{1}的结果,即
l n
现在您尝试将结果类型(->)
设为l
,这意味着
kn
但上面我们看到了*
,它产生了
l :: kn -> *
RESP。 node
,这是一种无限的。无限类型,如无限类型,是不允许的。但是,类推理只是非常基本的,所以编译器认为n l
的参数有n :: kl -> *
种,但从kl = kn -> *
看n :: (kn -> *) -> *
有种类{{1}因此,作为kn = (kn -> *) -> *
的参数,l
具有错误的类型,它不适用于足够的类型参数。
构造函数类的正常使用是单参数类
*
您必须从数据声明
中删除n l
然后上面的编译。不过,我认为它不会对你有所帮助。正如Chris Kuklewicz所说,你的类型追逐自己的尾巴,你将它们用作
n
对于多参数类,如编译器所说,你不能让对方的每个要求都导致依赖循环(同样,在你的约束中你只使用一个参数,
kl -> *
格式错误,如果循环被破坏,编译器会拒绝。
您可以通过合并类来解决周期,
l
但是您仍然遇到类型对此无用的问题。
我不太了解你的目标,建议一个可行的解决方案,抱歉。
答案 1 :(得分:4)
有人可以解释什么是错的吗?
在我解释错误消息之前的一个初始问题:多态数据类型很好,但最后必须使用具体类型。
使用类型* -> *
的SimpleNode和类型* -> *
的SimpleLinks,没有具体的类型:
SimpleNode (SimpleLink (SimpleNode (SimpleLink (SimpleNode (...
你不能拥有Haskell中的无限类型,尽管newtype和data会让你更接近:
type G0 = SimpleNode (SimpleLink G0) -- illegal
newtype G1 = G1 (SimpleNode (SimpleLink G1)) -- legal
data G2 = G2 (SimpleNode (SimpleLink G2)) -- legal
在创建类型类之前,您可能需要重新考虑数据类型。
现在转到错误消息说明:您的类型类Link
定义了一个函数node
class Link l where
node :: (Node n) => l -> n
node
是一个神奇的OOP工厂,根据l
的类型和价值,可以制作任何类型n
(由Node n
限定) node
愿望的来电者。此n
与您实例中的n
无关:
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
重复一遍:上面实例中的n
与n
定义中的node :: (Node n) => l -> n
不同。编译器生成一个相关但新鲜的名称n1
,并给出错误:
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
实例中的n
取自node
函数输入的类型(SimpleLink n)。 n1
是node
的调用者要求这个神奇的工厂生产的类型。如果n和n1相同,那么编译器会很高兴...但是你对类型类和实例的定义不会限制它,因此代码片段会被拒绝。
SimpleLink中的错误重复了类似的故事。没有银弹可以解决这个问题。我希望你需要重新思考和重新设计这个,可能是在阅读了其他人的代码之后,以便学习如何实现目标。
你的目标是什么?图形数据结构可以变化很多,细节也很重要。
答案 2 :(得分:1)
我正在打破堆栈溢出礼仪并添加第二个答案以保持这一点。这是一个带有未标记边的二分无向图的简单代码示例,可能对Factor Graph建模有用:
-- Bipartite graph representation, unlabeled edges
-- Data types to hold information about nodes, e.g. ID number
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
-- Node holds itself and a list of neighbors of the oppostite type
data Node selfType adjacentType =
N { self :: selfType
, adj :: [Node adjacentType selfType] }
-- A custom Show for Node to prevent infinite output
instance (Show a, Show b) => Show (Node a b) where
show (N x ys) = "Node "++ show x ++ " near " ++ show (map self ys)
-- Type aliases for the two node types that will be used
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
data FactorGraph = FG [VariableNode] [FactorNode] deriving (Show)
v1 = N (VV 1) [f1,f2]
v2 = N (VV 2) [f2]
v3 = N (VV 3) [f1,f3]
f1 = N (FV 1) [v1,v3]
f2 = N (FV 2) [v1,v2]
f3 = N (FV 3) [v3]
g = FG [v1,v2,v3] [f1,f2,f3]
答案 3 :(得分:0)
借助Chris Kuklewicz(http://stackoverflow.com/a/11450715/727827)的提示,我首先得到了我想要的代码。
但是,我认为Crhis的回答(使用*Vertex
来保存数据)简单而且更好。我要离开这里澄清我想要的东西。
class NodeClass n where
adjacent :: n a b -> [n b a]
data Node selfType adjacentType =
N
{ selfNode :: selfType
, adjNode :: [Node adjacentType selfType] }
data NodeWithData selfType adjacentType =
NWD
{ selfNodeWithData :: selfType
, adjNodeWithData :: [NodeWithData adjacentType selfType]
, getDataWithData :: [Double]
}
instance NodeClass Node where
adjacent = adjNode
instance NodeClass NodeWithData where
adjacent = adjNodeWithData
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
type VariableNodeWithData = NodeWithData VariableVertex FactorVertex
type FactorNodeWithData = NodeWithData FactorVertex VariableVertex