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.
Square
s. 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 Graphic
s 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
.