----------------------------------------------------------------------- -- Shape example, from Haskell craft, Ch 14 -- An existential type of shapes, built from the instances -- of the Shape type class. Based on Shape3. -- -- 21 June 2001 ----------------------------------------------------------------------- module Shape4 where -- The type of all shapes, i.e. all types conforming to the Sh -- interface, collected as a single existential type. data Shape = forall a. Sh a => Shape a -- If the type is to be called Shape, then the class needs to be -- renamed; here it's Sh, could be ShapeInterface. class Sh a where isRound :: a -> Bool area :: a -> Float perimeter :: a -> Float -- Pull the single data type into three separate types... data Circle = Circle Float data Rectangle = Rectangle Float Float data Triangle = Triangle Float Float Float -- To build examples need to wrap everything in the Shape -- constructor. These can become constructors (small 'c') of Shape. shape1 = Shape (Circle 3.0) shape2 = Shape (Rectangle 45.9 87.6) -- Reorganise the definitions, organising by sort of shape rather -- than by function. This is simply a matter of cutting and pasting -- lines in the file. instance Sh Circle where isRound (Circle _) = True area (Circle r) = pi*r*r perimeter (Circle r) = 2*pi*r instance Sh Rectangle where isRound (Rectangle _ _) = False area (Rectangle h w) = h*w perimeter (Rectangle h w) = 2*(h+w) instance Sh Triangle where isRound (Triangle _ _ _) = False area (Triangle x y z) = sqrt(s*(s-x)*(s-y)*(s-z)) where s = (x+y+z)/2 perimeter (Triangle x y z) = x+y+z -- Trying it out. Adding the type of ellipses. data Ellipse = Ellipse Float Float mkEllipse :: Float -> Float -> Shape mkEllipse x y = Shape (Ellipse x y) instance Sh Ellipse where isRound (Ellipse _ _) = True area (Ellipse h w) = pi*h/2*w/2 perimeter (Ellipse h w) = 2*(h/2+w/2) -- Finally make Shape an instance of Sh so that Shapes can be -- directly manipulated by the functions area etc, just like the -- original data type (except for the lack of pattern matching). instance Sh Shape where isRound (Shape sh) = isRound sh area (Shape sh) = area sh perimeter (Shape sh) = perimeter sh