By working through the steps in this handout, you will develop a HasCl program to draw a picture made up of many overlapping squares of different sizes and colors.
data Graphic = Square(Num, Num, Num, Color) | Over(Graphic, Graphic) | BlankThis says that a
Graphic value is either a single square or the
combination of one Graphic over another, or nothing at all. A
square needs four parameters--the value Square(x, y, w, c)
describes a square whose lower-left corner is at the point (x, y), with
width w and color c. The first three parameters, x, y, and w,
are all numbers expressing positions or distances relative to the
coordinate system of the graphics window: the lower-left corner is at
(- 50, - 50), and the upper-right corner is at (50, 50), regardless of the
actual size of the window. The color, c, is specified as a value of
the following data type, which is also defined in the Graphics module:
data Color = RGB(Num, Num, Num)The value
RGB(r, g, b) specifies a color with red, green, and
blue components given by the numbers r, g, and b, respectively,
where each component ranges from 0 (completely absent) to 255 (full
strength). The Graphics module also defines some useful constants of
type Color; for example, red is the value
RGB(255,0,0) (look in the module browser in Funnie to see what
other colors are defined).
Square(10, 20, 30, RGB(0, 255, 0)). If you type this in, the
system should pop-up a graphics window containing the square.
For testing, it will be convenient to define some sample squares. Enter each of the following in a separate definition window:
redGiant = Square(-20, -10, 50, RGB(255, 0, 0)) whiteDwarf = Square(10, 30, 20, RGB(255, 255, 255)) purpleMedium = Square(0, -20, 35, RGB(128, 0, 128))Now you can easily draw a square by entering its name, e.g.,
redGiant, in a Funnie expression window. However, this only lets
you draw one square at a time. To combine several squares in one
picture, we need the Over constructor of the Graphic data
type, as follows: Over(redGiant, whiteDwarf). Notice how the
squares are combined, and see what happens if you reverse the order of
the squares.
Squares. We will need a function
which takes a list of squares and combines them all
into a single Graphic. As usual when working with a list of
things, we will define the function by recursion. Here is the base case,
which uses the special value Blank to produce a blank
picture:
showSquareList([ ]) = BlankThe recursive case will have the following form:
showSquareList([s : ss]) =When this pattern matches,
s will be the first square on the
list, and ss will be a list of the remaining squares. Write an
appropriate right-hand side for this case of the function. The square
s is already a Graphic; you will need to use
showSquareList to produce another Graphic from ss.
These two Graphics will then need to be combined into one with
Over. When you have defined the function, try it out with
showSquareList([redGiant, whiteDwarf]).
diagonalSquares(x, y, d, rgb, 0) = [ ]
diagonalSquares(x, y, d, rgb, n) = [Square(x, y, d, rgb) :
diagonalSquares(x+d/2, y+d/2, d, rgb, n-1)]
After entering this function, evaluate
showSquareList(diagonalSquares(-30, -30, 10, white, 9)).
The cases for this function mean that diagonalSquares(x, y, d, rgb, n)
will produce a list of n squares (because the list is empty
when n is 0, and it gets one extra element for each
recursive call as n counts down to 0). The first one will
have its corner at (x,y), with width d and color
rgb. Succeeding squares will be offset by adding d/2 to the
x and y coordinates of the corner; the effect will be that
each square will be centered on the upper-right corner of the previous
one. You should get a picture that looks like a white staircase.
vanishingSquares which is similar to diagonalSquares
except replace the size argument d in the recursive call (to
vanishingSquares, of course) with the expression d*3/4.
To try this out, you will probably want to start with a larger
initial square; something like this should work:
showSquareList(vanishingSquares(-30, -30, 20, white, 7))
++. Here
is a skeleton of the code for you to fill in:
squareDesign(x, y, d, rgb, 0) =
squareDesign(x, y, d, rgb, n) = [Square(x, y, d, rgb) :
squareDesign(x-d/4, y-d/4, d/2, rgb, n-1) ++
squareDesign(x-d/4, y+3*d/4, d/2, rgb, n-1) ++
squareDesign( ) ++
squareDesign( )]
When you have successfully compiled the finished function, try
evaluating the following expression:
showSquareList(squareDesign(-20, -20, 40, white, 4)).
You can change the 4 to 5 to draw one more level, but it
will take too long if you try to do 6 or more levels (each level has
four times as many squares, so there are 1024 squares at level 6).
lessRed and
lessGreen, each of type (Color) -> Color. Here is one:
lessRed(RGB(r, g, b)) = RGB(r/2, g, b)You will need to enter this and a similar definition for
lessGreen, then write a new function similar to
squareDesign that calls these functions in the appropriate
places. Call this new function colorDesign, and test it.
2; for
example, if you modify colorDesign, then your new function should
be named colorDesign2.