类型类,重载和实例声明

时间:2014-01-15 22:15:59

标签: haskell types ghci

有这个:

data Rectangle = Rectangle Height Width
data Circle = Circle Radius

class Shape a where
    area :: a -> Float
    perimeter :: a -> Float

instance Shape Rectangle where
    area (Rectangle h w) = h * w
    perimeter (Rectangle h w) = 2*h+w*2

instance Shape Circle where
    area (Circle r) = pi * r**2
    perimeter (Circle r) = 2*pi*r

volumenPrism base height = (area base) * height

surfacePrism shape h = (area shape) * 2 + perimeter shape * h

为什么我不能写这个? a是一种类型,为什么这不起作用?

instance (Shape a) => Eq a where
      x==y = area x == area y

显然这样做:

instance Eq Circle where
     x==y = area x == area y

首先是Circle,然后是Rectangle的工作......但似乎不是正确的方法。

我不知道这是什么?

1 个答案:

答案 0 :(得分:7)

基本问题是类型类实例解析机制没有回溯。因此,如果您编写instance Shape a => Eq a,那么每当编译器想要找到Eq实例时,编译器将尝试使用此实例,对于大多数类型,它将无法解决,因为它们不是Shape

如果您仍然想要这样做,可以添加

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

位于源文件的顶部。

您还可以通过将OverlappingInstances添加到LANGUAGE编译指示集来解决上述问题,但您仍然会有Eq的全局实例,这会导致其他地方出现严重混淆你的计划。

只要枚举你真正需要的实例,即使它看起来很丑,也要好得多。您可以使用辅助函数将样板文件保持在最小值,例如

x `areaEq` y = area x == area y

然后

instance Eq Circle where
    (==) = areaEq