Clean

Contributed by Chris Rathman

Shape Interface (Shape.dcl)

definition module Shape

// declare method interfaces for the shape superclass
class ShapeClass 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 :: *World a -> *World

Shape Implementation (Shape.icl)

implementation module Shape
import StdEnv

// declare method interfaces for the shape superclass
class ShapeClass 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 :: *World a -> *World

Rectangle Interface (Rectangle.dcl)

definition module Rectangle
import Shape

// declare method interfaces for rectangle subclass
class RectangleClass a | ShapeClass a where
   getWidth :: a -> Int
   getHeight :: a -> Int
   setWidth :: a Int -> a
   setHeight :: a Int -> a

// declare the record to hold rectangle parameters
::RectangleRecord

// declare the constructor for rectangle class
MakeRectangle :: Int Int Int Int -> RectangleRecord

// define the methods for shape superclass
instance ShapeClass RectangleRecord

// define the methods for rectangle subclass
instance RectangleClass RectangleRecord

Rectangle Implementation (Rectangle.icl)

implementation module Rectangle
import StdEnv
import Shape

// declare method interfaces for rectangle subclass
class RectangleClass a | ShapeClass a where
   getWidth :: a -> Int
   getHeight :: a -> Int
   setWidth :: a Int -> a
   setHeight :: a Int -> a

// declare the record to hold rectangle parameters
::RectangleRecord =
   {   x :: Int
   ,   y :: Int
   ,   width :: Int
   ,   height :: Int
   }

// declare the constructor for rectangle class
MakeRectangle :: Int Int Int Int -> RectangleRecord
MakeRectangle initx inity initwidth initheight =
   {   x = initx
   ,   y = inity
   ,   width = initwidth
   ,   height = initheight
   }

// define the methods for shape superclass
instance ShapeClass RectangleRecord where
   getX a = a.x
   getY a = a.y
   setX a newx = {a & x = newx}
   setY a newy = {a & y = newy}
   moveTo a newx newy = {a & x = newx, y = newy}
   rMoveTo a newx newy = {a & x = ((getX a) + newx), y = ((getY a) + newy)}
   draw world a
      #  (console, world) = stdio world
         console = fwrites "Drawing a Rectangle at:(" console
         console = fwritei (getX a) console
         console = fwrites "," console
         console = fwritei (getY a) console
         console = fwrites "), width " console
         console = fwritei (getWidth a) console
         console = fwrites ", height " console
         console = fwritei (getHeight a) console
         console = fwrites "\n" console
         (ok, world) = fclose console world
      |  not ok = abort "Cannot open console"
      = world

// define the methods for rectangle subclass
instance RectangleClass RectangleRecord where
   getWidth a = a.width
   getHeight a = a.height
   setWidth a newwidth = {a & width = newwidth}
   setHeight a newheight = {a & height = newheight}

Circle Interface (Circle.dcl)

definition module Circle
import Shape

// declare method interfaces for circle subclass
class CircleClass a | ShapeClass a where
   getRadius :: a -> Int
   setRadius :: a Int -> a

// declare the record to hold circle parameters
::CircleRecord

// declare the constructor for circle class
MakeCircle :: Int Int Int -> CircleRecord

// define the methods for shape superclass
instance ShapeClass CircleRecord

// define the methods for circle subclass
instance CircleClass CircleRecord

Circle Implementation (Circle.icl)

implementation module Circle
import StdEnv
import Shape

// declare method interfaces for circle subclass
class CircleClass a | ShapeClass a where
   getRadius :: a -> Int
   setRadius :: a Int -> a

// declare the record to hold circle parameters
::CircleRecord =
   {   x :: Int
   ,   y :: Int
   ,   radius :: Int
   }

// declare the constructor for circle class
MakeCircle :: Int Int Int -> CircleRecord
MakeCircle initx inity initradius =
   {   x = initx
   ,   y = inity
   ,   radius = initradius
   }

// define the methods for shape superclass
instance ShapeClass CircleRecord where
   getX a = a.x
   getY a = a.y
   setX a newx = {a & x = newx}
   setY a newy = {a & y = newy}
   moveTo a newx newy = {a & x = newx, y = newy}
   rMoveTo a newx newy = {a & x = ((getX a) + newx), y = ((getY a) + newy)}
   draw world a
      #  (console, world) = stdio world
         console = fwrites "Drawing a Circle at:(" console
         console = fwritei (getX a) console
         console = fwrites "," console
         console = fwritei (getY a) console
         console = fwrites "), radius " console
         console = fwritei (getRadius a) console
         console = fwrites "\n" console
         (ok, world) = fclose console world
      |  not ok = abort "Cannot open console"
      = world

// define the methods for circle subclass
instance CircleClass CircleRecord where
   getRadius a = a.radius
   setRadius a newradius = {a & radius = newradius}

Try shapes module (Polymorph.icl)

module Polymorph
import StdEnv
import Shape, Rectangle, Circle

Start :: *World -> *World
Start world
   // handle the shapes polymorphically
   # world = drawloop world scribble1
   # world = drawloop world scribble2

   // handle rectangle specific instance
   # world = draw world arectangle
   # world = draw world (setWidth arectangle 30)

   = world

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 world [] = world
drawloop world [head:tail]
   # world = draw world head
   # movedShape = rMoveTo head 100 100
   # world = draw world movedShape
   = drawloop world tail

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
65536

Chris Rathman / Chris.Rathman@tx.rr.com