使用类型类访问 Haskell 中相似数据类型的字段
Using a typeclass to access fields of similar data types in Haskell
我正在 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:Edgeclass定义中的return值是自由类型变量,因此无法与b_endpoints
和[=的return值匹配17=],等等
我确实需要类型变量——顶点可以是字符、字符串、整数等。边权重可以是任何类型的数字(浮点数有助于解决某些问题)。颜色甚至可以是构造数据类型。
有没有 "idiomatic" 语言的方法来做到这一点?看起来这是一种基本类型的多态性,但我正在努力理解如何实现它。
提前感谢您的帮助,请理解我过去一天一直在互联网上搜索指导。很难为这个问题构建搜索查询。
您的类型 class 可以通过在 class 定义中包含类型参数 v
和 w
来修复。
class Edge e where
endpoints :: e v w -> (v,v)
weight :: e v w -> w
现在 e
具有 * -> * -> *
类型,这意味着它需要是一个带有两个额外类型参数的类型,然后这些参数将用于 endpoints
和 weight
实际上 link 结果类型到边的类型。
但是,您需要稍微调整一下 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
class 中成为关联类型的同义词。这样,在实例类型中输入参数的顺序就变得无关紧要了。
{-# 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
然而,通常类型classes并不是这种多态性的最佳解决方案。我会简单地在您的 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 中处理一些图形问题。在工作进行到一半时,我决定要能够在图形数据类型中表示边缘颜色。所以我从边缘开始:边缘可以是彩色的也可以是无色的。这是我在想什么的快速模型。请记住,我知道此代码中存在严重缺陷。
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:Edgeclass定义中的return值是自由类型变量,因此无法与b_endpoints
和[=的return值匹配17=],等等
我确实需要类型变量——顶点可以是字符、字符串、整数等。边权重可以是任何类型的数字(浮点数有助于解决某些问题)。颜色甚至可以是构造数据类型。
有没有 "idiomatic" 语言的方法来做到这一点?看起来这是一种基本类型的多态性,但我正在努力理解如何实现它。
提前感谢您的帮助,请理解我过去一天一直在互联网上搜索指导。很难为这个问题构建搜索查询。
您的类型 class 可以通过在 class 定义中包含类型参数 v
和 w
来修复。
class Edge e where
endpoints :: e v w -> (v,v)
weight :: e v w -> w
现在 e
具有 * -> * -> *
类型,这意味着它需要是一个带有两个额外类型参数的类型,然后这些参数将用于 endpoints
和 weight
实际上 link 结果类型到边的类型。
但是,您需要稍微调整一下 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
class 中成为关联类型的同义词。这样,在实例类型中输入参数的顺序就变得无关紧要了。
{-# 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
然而,通常类型classes并不是这种多态性的最佳解决方案。我会简单地在您的 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