我正在处理Haskell中的一些图形问题。在我的工作中,我决定我希望能够在图形数据类型中表示边缘颜色。所以我从边缘开始:边缘可以是彩色的也可以是未着色的。这里是我正在考虑的事情的快速模型。请记住,我知道此代码中存在可怕的缺陷。
data BasicEdge v w = BasicEdge { b_endpoints :: (v,v), b_weight :: w}
data ColoredEdge v w c = ColoredEdge { c_endpoints :: (v,v), c_weight :: w, color :: c}
class Edge e where
endpoints :: e -> (v,v)
weight :: e -> w
instance Edge (BasicEdge v w) where
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge v w c) where
endpoints = c_endpoints
weight = c_weight
问题1:BasicEdge中的v
和w
是与ColoredEdge中的v
和w
不同的类型变量。因此,尝试以多态方式访问它们是荒谬的。
问题2:Edge类定义中的返回值是自由类型变量,因此它们无法与b_endpoints
和c_endpoints
等的返回值匹配。
我确实需要类型变量 - 顶点可以是字符,字符串,整数等。边缘权重可以是任何类型的数字(浮点数对某些问题有帮助)。颜色甚至可以是构造的数据类型。
是否存在"惯用"在语言中这样做的方法?看来这是一种基本类型的多态,但我很难理解如何实现它。
在此先感谢您的帮助,请理解我过去一天在互联网上寻求指导。很难为此问题构建搜索查询。
答案 0 :(得分:6)
可以通过在类定义中包含类型参数v
和w
来修复类型类。
class Edge e where
endpoints :: e v w -> (v,v)
weight :: e v w -> w
现在e
具有* -> * -> *
种类,这意味着它需要是一个带有两个额外类型参数的类型,然后在endpoints
和weight
中使用这些参数实际上将结果类型链接到边缘的类型。
但是,您需要稍微调整ColoredEdge
类型,以便v
和w
是最后两个参数,所以
data BasicEdge v w = BasicEdge { b_endpoints :: (v,v), b_weight :: w}
data ColoredEdge c v w = ColoredEdge { c_endpoints :: (v,v), c_weight :: w, color :: c}
现在您可以将实例定义为
instance Edge BasicEdge where
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge c) where
endpoints = c_endpoints
weight = c_weight
另一种选择是使用TypeFamilies
语言扩展,并使Edge
类中的顶点和权重类型相关联的类型为同义词。这样,在实例类型中键入参数的顺序就变得无关紧要了。
{-# LANGUAGE TypeFamilies #-}
class Edge e where
type Vertex e
type Weight e
endpoints :: e -> (Vertex e, Vertex e)
weight :: e -> Weight e
instance Edge (BasicEdge v w) where
type Vertex (BasicEdge v w) = v
type Weight (BasicEdge v w) = w
endpoints = b_endpoints
weight = b_weight
instance Edge (ColoredEdge v w c) where
type Vertex (ColoredEdge v w c) = v
type Weight (ColoredEdge v w c) = w
endpoints = c_endpoints
weight = c_weight
但是,通常类型类不是这种多态的最佳解决方案。我只需在Edge
类型中为任何其他数据添加一个额外参数,如
data Edge v w d = Edge { endpoints :: (v,v), weight :: w, edgeData :: d }
现在,您可以在d
中添加颜色,或者为包含多个数据字段的记录添加颜色,并仍然以通用方式查询图形的形状。
您的原始边缘类型现在可以使用类型同义词
表示type BasicEdge v w = Edge v w ()
type ColoredEdge v w c = Edge v w c