在超类函数

时间:2017-08-29 03:30:30

标签: haskell functional-programming subclass typeclass class-hierarchy

在我的Haskell程序中,我有一些类型表示"形状"的抽象概念,即

-- | Class representing shapes.
class Shape a where
  isColliding :: (Shape b) => a -> b -> Bool
  centroid :: Point

-- | Class representing shapes composed of a finite number of vertices 
and line segments connecting them.
class (Shape a) => Polygon a where
  vertices :: a -> Vertices 

如您所见,Polygon自然是Shape的子类。我也有一些数据类型是这些不同类型类的实例。例如:

data Box = Box Point Point Angle

instance Shape Box where
  ...

instance Polygon Box where
  ...

---------------------------------

data Circle = Circle Point Radius

instance Shape Circle where
  ...

我有更多可能的形状,例如NGonRegularNGon等。我希望能够实现isColliding,但是计算两个形状是否为碰撞取决于Shape的特定实例的实现。例如,要计算两个框是否发生碰撞,我需要它们的顶点列表。所以我有几个问题:

  1. 无论如何,"专门化"我的函数isColliding,以便以特定的方式定义isColliding :: (Polygon b) => Box -> b -> Bool类型的碰撞?
  2. 我的数据类型的结构是解决此问题的最佳方法,还是在重构整个事物以消除此问题时,我是否滥用了类型类和数据类型?
  3. 我对Haskell很陌生,所以如果我的问题措辞不当或需要澄清,请告诉我。

1 个答案:

答案 0 :(得分:9)

您当前的Shape班级说“isColliding可以判断此形状是否与另一个形状相交,只使用另一个形状上的Shape 方法”,因为其签名(Shape b) => a -> b -> Bool仅告诉您b的实例为Shape。所以你说得对,这不是你想要的。

您可以做的一件事是使用MultiParamTypeClasses来描述两种类型之间的关系

{-# LANGUAGE MultiParamTypeClasses #-}

class Colliding a b where
  collidesWith :: a -> b -> Bool

然后为各种类型的具体组合创建实例:

instance Colliding Circle Box where
  Circle p r `collidesWith` Box p1 p2 θ = {- … -}

在定义实现时,您知道ab的具体类型。这对你的用例来说可能已经足够了。

但是,如果您有 n 类型,则会留下 n 2 实例。如果你试图定义像这样的多态实例,你会遇到问题:

instance (HasBoundingBox b) => Colliding Circle b where
  collidesWith = {- … -}

因为此与<{1}}的所有其他实例重叠Colliding Circle将匹配任何类型,并且只添加{{{ 1}}必须有b的实例。在实例解析后检查该约束。您可以使用b或较新的HasBoundingBox / OverlappingInstances / OVERLAPPABLE pragma解决此问题,以告知GHC选择最具体的匹配实例,但如果你刚刚熟悉Haskell,这可能比它的价值更麻烦。

我不得不考虑更多,但肯定有其他方法。在最简单的情况下,如果您只需要处理几种不同的形状,那么您可以将它们设为单个和类型而不是单独的数据类型:

OVERLAPPING

然后,您的OVERLAPS函数可以是data Shape = Circle Point Radius | Box Point Point Angle | … 类型,只是在此类型上匹配模式。

一般来说,如果您正在编写类型类,那么它应该附带 law ,以了解实例的行为方式,例如来自isColliding的{​​{1}}。如果你不能想到任何应该总是适用于你的类实例的方程式,你应该更喜欢使用普通的旧函数和数据类型来表示事物。