类型类,重载和实例声明

t0m*_*ma5 4 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
Run Code Online (Sandbox Code Playgroud)

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

instance (Shape a) => Eq a where
      x==y = area x == area y
Run Code Online (Sandbox Code Playgroud)

显然这样做:

instance Eq Circle where
     x==y = area x == area y
Run Code Online (Sandbox Code Playgroud)

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

什么是我没有涉及到这一切?

GS *_*ica 7

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

如果你真的想要这样做,你可以添加

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}
Run Code Online (Sandbox Code Playgroud)

在源文件的顶部.

您还可以通过添加OverlappingInstancesLANGUAGE编译指示集来解决上述问题,但是您仍然会有一个全局实例,Eq这将导致程序中其他地方出现严重混淆.

最好只列举你真正需要的实例,即使它看起来很难看.您可以使用辅助函数将样板保持在最小值,例如

x `areaEq` y = area x == area y
Run Code Online (Sandbox Code Playgroud)

然后

instance Eq Circle where
    (==) = areaEq
Run Code Online (Sandbox Code Playgroud)

等等