haskell - 在 Haskell 中使用类型类访问相似数据类型的字段

标签 haskell graph polymorphism typeclass

我正在用 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:vw BasicEdge 中的类型变量与 v 不同和w在彩色边缘。因此,尝试以多态方式访问它们是 absurd 的。

问题2:Edge类定义中的返回值是自由类型变量,因此无法与b_endpoints的返回值匹配和c_endpoints

我确实需要类型变量 - 顶点可以是字符、字符串、整数等。边权重可以是任何类型的数字(浮点对某些问题很有帮助)。颜色甚至可以是构造的数据类型。

是否有一种“惯用”的方式可以用语言来做到这一点?看起来这是多态性的基本类型,但我很难理解如何实现它。

预先感谢您的帮助,请理解我过去一天一直在尝试在互联网上搜索指导。很难为这个问题构建搜索查询。

最佳答案

可以通过在类定义中包含类型参数 vw 来修复您的类型类。

class Edge e where
    endpoints :: e v w -> (v,v)
    weight :: e v w -> w

现在 e 具有 * -> * -> * 类型,这意味着它需要是一个带有两个附加类型参数的类型,然后将这些参数用于endpointsweight 将结果类型实际链接到边缘类型。

但是,您需要稍微调整 ColoredEdge 类型,以便 vw 是最后两个参数,因此

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

关于haskell - 在 Haskell 中使用类型类访问相似数据类型的字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30307450/

相关文章:

regex - Haskell 中的正则表达式与词法分析器

algorithm - 寻找 "Count Sequence"

Haskell 打印不带换行符的字符串

C++ : inheritance without virtuality

arrays - Haskell 多态数组操作

Haskell迭代器: simple worked example of stripping trailing whitespace

java - 图的自动布局 (JGraphX)

python - python中图的深度复制

使用动态编程进行字符串操作

c++ - 如果派生类具有私有(private)变量,则派生类数组不起作用