{ |one, step, back| }

The Shape Example in Haskell

Contributed by Chris Rathman

Code for Haskell

File: Shape.hs

module Shape(Shape, getX, getY, setX, setY, moveTo, rMoveTo, draw)

   where

   -- declare method interfaces for the shape superclass
   class Shape a where
      getX :: a -> Int
      getY :: a -> Int
      setX :: a -> Int -> a
      setY :: a -> Int -> a
      moveTo :: a -> Int -> Int -> a
      rMoveTo :: a -> Int -> Int -> a
      draw :: a -> IO()

File: Circle.hs

module Circle(Circle, MakeCircle, getRadius, setRadius)

   where
   import Shape

   -- declare method interfaces for circle subclass
   class Shape a => Circle a where
      getRadius :: a -> Int
      setRadius :: a -> Int -> a

   -- define the methods for shape superclass
   instance Shape CircleInstance where
      getX = x
      getY = y
      setX a newx = a {x = newx}
      setY a newy = a {y = newy}
      moveTo a newx newy = a {x = newx, y = newy}
      rMoveTo a deltax deltay = a {x = ((getX a) + deltax), y = ((getY a) + deltay)}
      draw a =
         putStrLn ('Drawing a Circle at:(' ++ (show (getX a)) ++ ',' ++ (show (getY a)) ++
            '), radius ' ++ (show (getRadius a)))

   -- define the methods for circle subclass
   instance Circle CircleInstance where
      getRadius = radius
      setRadius a newradius = a {radius = newradius}

   -- declare the constructor for circle class
   data CircleInstance = MakeCircle {x, y, radius :: Int}
      deriving(Eq, Show)

File: Rectangle.hs

module Rectangle(Rectangle, MakeRectangle, getWidth, getHeight, setWidth, setHeight)

   where
   import Shape

   -- declare method interfaces for rectangle subclass
   class Shape a => Rectangle a where
      getWidth :: a -> Int
      getHeight :: a -> Int
      setWidth :: a -> Int -> a
      setHeight :: a -> Int -> a

   -- define the methods for shape superclass
   instance Shape RectangleInstance where
      getX = x
      getY = y
      setX a newx = a {x = newx}
      setY a newy = a {y = newy}
      moveTo a newx newy = a {x = newx, y = newy}
      rMoveTo a deltax deltay = a {x = ((getX a) + deltax), y = ((getY a) + deltay)}
      draw a =
         putStrLn ('Drawing a Rectangle at:(' ++ (show (getX a)) ++ ',' ++ (show (getY a)) ++
            '), width ' ++ (show (getWidth a)) ++ ', height ' ++ (show (getHeight a)))

   -- define the methods for rectangle subclass
   instance Rectangle RectangleInstance where
      getWidth = width
      getHeight = height
      setWidth a newwidth = a {width = newwidth}
      setHeight a newheight = a {height = newheight}

   -- declare the constructor for rectangle class
   data RectangleInstance = MakeRectangle {x, y, width, height :: Int}
      deriving(Eq, Show)

File: Polymorph.hs

module Polymorph(main)

   where
   import Shape
   import Circle
   import Rectangle

   main =
      do
         -- handle the shapes polymorphically
         drawloop scribble1
         drawloop scribble2

         -- handle rectangle specific instance
         draw arectangle
         draw (Rectangle.setWidth arectangle 30)

      where
         -- create lists containing instances of each shape
         scribble1 = (MakeCircle 15 25 8):[]
         scribble2 = (MakeRectangle 10 20 5 6):[]

         -- create a rectangle instance
         arectangle = (MakeRectangle 0 0 15 15)

   -- iterate through the list of shapes and draw
   drawloop [] = return True
   drawloop (x:xs) =
      do
         draw x
         draw shapeMoved
         drawloop xs
      where
         shapeMoved = (Shape.rMoveTo x 100 100)

File: Polymorph.prj

Shape.hs
Circle.hs
Rectangle.hs
Polymorph.hs

Output

Drawing a Circle at:(15,25), radius 8
Drawing a Circle at:(115,125), radius 8
Drawing a Rectangle at:(10,20), width 5, height 6
Drawing a Rectangle at:(110,120), width 5, height 6
Drawing a Rectangle at:(0,0), width 15, height 15
Drawing a Rectangle at:(0,0), width 30, height 15