Haskell For Kids: Week 4

Welcome back to our weekly report on the Haskell for Kids class! We did three big things this week, so let’s just jump in!

New Student!

First of all, we gained a student in my class, so we all welcomed Skyler! We’re three weeks in, but this gave us a great chance to go back over some of the basic ideas we’ve already seen. These include:

The first week, we talked about what computer programming is, what a compiler is, and what a library does for you. We also introduced the basics of programming using the Haskell programming language and the Gloss library, and we played around. So we reviewed the basics of that. Here’s a link to the Week 1 Summary. The second week, we talked about the basic structure of a program, including what an import statement means, how to write definitions of variables, and the idea of expressions. We also looked at how useful it is to stay organized and make sure everything in your program is where it belongs. Here’s a link to the Week 2 Summary. Finally, the third week, we talked about cartesian (x,y) coordinates and lines and polygons, and we practiced “playing computer” and predicting what the computer is going to draw when it sees programs we made up. Here’s a link to the Week 3 Summary.

Skyler joining gave us a chance to go back and review that, and practice explaining it to someone new. I think most people learned something new of their own, too.

Practicing Top-Down Design

Another thing we did this week was practice some of the ideas we’ve touched on briefly in the past:

Top-down design

Organizing and naming things

Writing stubs

We did this by working through an example in class, in great detail. I’ll try to reproduce that here. You can follow along, as always, at http://dac4.designacourse.com:8000/ Remember, the point of this isn’t just to skip ahead and look at the final result: it’s to follow through the steps of how we got there. We used techniques that you can use to try to write your own programs, too!

It does get repetitive, though, so at each step (except the last), I’ve bolded the parts of the program that are new, so you can generally ignore anything that’s not in bold because you’ve seen it before.

The Goal

Our goal will be to draw a dinner plate. Here’s a whiteboard drawing of our goal:

We’ll start out by writing a basic program to draw an empty picture. We may not have used it before, but blank is defined by Gloss to be an empty picture.

import Graphics.Gloss picture = blank

If we run this program, the result looks rather boring…

So far, so… boring. But there’s something worth pointing out. Defining picture to be blank was called a “stub”. We just stuck something in to make the program complete, knowing it was obviously not enough. That’s okay, so long as we remember the places we’ve used stubs so we can go back and fill them in later.

The first thing we’ll do is declare that our picture is a dinner. That looks something like this. We’ll also start adding comments (remember, those of bits of the program that are ignored by the computer) to remind ourselves where we’ve got stubs.

import Graphics.Gloss picture = dinner dinner = blank -- stub

This looks the same as before; we’ve just said that the picture is a dinner… and that a dinner is blank. It might seem pointless, but don’t underestimate the chance to name things! This will come in handy later.

Let’s fill in the stub for dinner with the major parts of the dinner we’d like to draw. If you look at the plan, you can see it’s roughly divided into a plate, some food, a knife, and a fork. I’ll throw in a table, too, which is just the background for the entire image. Here’s our attempt to expand on the program:

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, fork, knife ] table = blank -- stub plate = blank -- stub food = blank -- stub fork = blank -- stub knife = blank -- stub

This might not look impressive when it’s done, but we’re working on understanding how to break down the picture into pieces. Let’s pick out a few easy pieces to draw, now. First, the table is just a 500 by 500 rectangle (in other words, the entire screen), colored a good table color, like brown.

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, fork, knife ] table = color brown (rectangleSolid 500 500) plate = blank -- stub food = blank -- stub fork = blank -- stub knife = blank -- stub

Let’s compile and run that…

Not in scope: `brown'

Oops! We used the color brown, but that’s not defined by Gloss. We can define it, though. Brown is, generally speaking, a dark orange, so let’s say so:

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, fork, knife ] table = color brown (rectangleSolid 500 500) plate = blank -- stub food = blank -- stub fork = blank -- stub knife = blank -- stub brown = dark orange

Now we’ll try again.

Looks good! Time to add the plate. We want to draw a rim on the plate, so it will consist of two circles — one on top of the other, and a little smaller. We’ll also want two new colors: gray and lightGray. This shouldn’t be difficult, so we’ll write it.

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, fork, knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = blank -- stub fork = blank -- stub knife = blank -- stub brown = dark orange lightGray = dark white gray = dark lightGray

I did something a little tricky with the colors. I could have defined gray to be dark (dark white), but it was easier to use the other color, lightGray, that I’d already defined. Either one would mean the same thing. Can you see why?

We’ll now build and run this program, and check the result.

As you can see, this is coming along fine. Time to do something about that silverware that’s stubbed out. What do we know about it? Let’s make a list:

We want a fork and a knife, both.

We want them to be in the middle vertically, but on different sides, about 200 pixels over.

They will be much taller than they are wide… maybe 300 pixels tall, but only 50 wide.

We’ll stop there, rather than trying to do everything at once. Remember, the idea is to work in small steps, filling in a few details at a time. So for now, we’ll ignore the unique shapes of forks and knives, and just make them rectangles. Because where we put the fork and knife isn’t really a part of what it means to be a fork or knife, those translations should go in dinner, not fork or knife. The result looks like this.

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = blank -- stub fork = rectangleWire 50 300 -- stub knife = rectangleWire 50 300 -- stub brown = dark orange lightGray = dark white gray = dark lightGray

Notice that I’ve stilled marked fork and knife as stubs. They are! That’s certainly not what they look like. But it just helped to draw an outline of the region of the plate where they belong. Let’s compile and run this, and see what happens.

It’s about time we start filling in the food. We’ll start out by breaking it down into the three main pieces, and then again stub them out with outlines rather than get into the details of what each piece looks like. Each piece of food is translated and rotated a little.

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = pictures [ translate (-50) ( 50) (rotate ( 45) carrot), translate (-20) (-40) (rotate ( 20) broccoli), translate ( 60) (-30) (rotate (-10) broccoli) ] carrot = rectangleWire 40 80 -- stub broccoli = rectangleWire 80 80 -- stub fork = rectangleWire 50 300 -- stub knife = rectangleWire 50 300 -- stub brown = dark orange lightGray = dark white gray = dark lightGray

Don’t worry if you couldn’t figure out all those numbers right off! When we wrote this in class, we had to guess and then tweak them until the rectangles ended up in about the right places. Being able to do that before we worry about the details of what broccoli is shaped like is one of the reasons we like stubs like this! (Also, don’t worry if you didn’t know how to spell broccoli. I had to look it up, too.)

Let’s run this and see what it looks like.

We’re now going to play our next trick. We’d like to focus on how to draw a carrot. But since the carrot is translated and rotated, it’s hard for us to focus on just that piece. Remember when we wrote picture = dinner earlier? I promised that would come in handy! We’re going to, just for now, change that to say picture = carrot. Our program now looks like this:

import Graphics.Gloss picture = carrot dinner = pictures [ table, plate, food, translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = pictures [ translate (-50) ( 50) (rotate ( 45) carrot), translate (-20) (-40) (rotate ( 20) broccoli), translate ( 60) (-30) (rotate (-10) broccoli) ] carrot = rectangleWire 40 80 -- stub broccoli = rectangleWire 80 80 -- stub fork = rectangleWire 50 300 -- stub knife = rectangleWire 50 300 -- stub brown = dark orange lightGray = dark white gray = dark lightGray

When we run this, we’ll have told the computer all about dinners and forks and knives and everything… but in the end, only asked it to draw a carrot. That’s fine; the computer is happy to ignore our definitions of variables that we don’t really use! The result looks like this.

So we’ve gotten rid of everything except the carrot, which of course looks like just a rectangle for now. Having escaped from the distractions of forks and broccoli, it shouldn’t be too hard to tell what a carrot is! It’s just a polygon colored orange. After some experimentation, you might end up with this:

import Graphics.Gloss picture = carrot dinner = pictures [ table, plate, food, translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = pictures [ translate (-50) ( 50) (rotate ( 45) carrot), translate (-20) (-40) (rotate ( 20) broccoli), translate ( 60) (-30) (rotate (-10) broccoli) ] carrot = color orange (polygon [ (-5, -40), (-20, 40), (20, 40), (5, -40) ]) broccoli = rectangleWire 80 80 -- stub fork = rectangleWire 50 300 -- stub knife = rectangleWire 50 300 -- stub brown = dark orange lightGray = dark white gray = dark lightGray

That looks like this:

Now, having gotten the look of a carrot under control, let’s change the definition of picture, so that the entire dinner will be drawn again.

import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), color lightGray (circleSolid 150) ] food = pictures [ translate (-50) ( 50) (rotate ( 45) carrot), translate (-20) (-40) (rotate ( 20) broccoli), translate ( 60) (-30) (rotate (-10) broccoli) ] carrot = color orange (polygon [ (-5, -40), (-20, 40), (20, 40), (5, -40) ]) broccoli = rectangleWire 80 80 -- stub fork = rectangleWire 50 300 -- stub knife = rectangleWire 50 300 -- stub brown = dark orange lightGray = dark white gray = dark lightGray

Hopefully, you can see how this will end up. One by one, for each of the remaining pieces of the program, we’ll do three things:

Change the definition of picture to focus on that piece. Write a program to properly draw that piece. Change the definition of picture again to draw the entire dinner.

In the interest of space, I’m skipping the remaining steps, but here’s the program we ended up with:

{- Picture of a dinner plate This program draws a dinner plate, with several food items and silverware. -} import Graphics.Gloss picture = dinner dinner = pictures [ table, plate, food, -- Silverware: translate ( 200) 0 fork, translate (-200) 0 knife ] table = color brown (rectangleSolid 500 500) plate = pictures [ color gray (circleSolid 175), -- rim color lightGray (circleSolid 150) -- center ] food = pictures [ translate (-50) ( 50) (rotate 45 carrot), translate (-20) (-40) (rotate 20 broccoli), translate ( 60) (-30) (rotate (-10) broccoli) ] carrot = color orange (polygon [ (-5, -40), (-20, 40), (20, 40), (5, -40) ]) broccoli = color (dark green) (pictures [ translate ( 0) (-15) (rectangleSolid 30 50), -- base translate (-15) ( 0) (circleSolid 25), -- flower translate ( 15) ( 0) (circleSolid 25), -- flower translate ( 0) ( 15) (circleSolid 25) -- flower ]) fork = color lightGray (pictures [ rectangleSolid 10 250, -- handle translate ( 0) ( 80) (rectangleSolid 40 10), -- base translate (-15) (100) (rectangleSolid 10 45), -- left prong translate ( 15) (100) (rectangleSolid 10 45) -- right prong ]) knife = color lightGray (pictures [ translate 0 (-25) (rectangleSolid 30 200), -- handle polygon [ (-15, 75), ( -5, 105), ( 15, 125), ( 15, 75) ] -- blade ]) {- Some colors that are used in the picture: -} brown = dark orange lightGray = dark white gray = dark lightGray

(We also added some comments to explain a little more and divide up the program into sections. And here is the final picture.

Voila! We have finished. The important thing to learn is how we were able to draw the whole picture by first just sketching out the major parts, and then filling in the details bit by bit. That’s the idea of top down design, which is a very good way to go about writing computer programs.

Oh no! Exam Time!

We’ve been working on and talking about pictures for a while, and some of us are getting antsy to move on to something else. Before we can, though, we need to be sure we all understand the ideas we’ve learned in writing our picture programs. So here it is: time to demonstrate a complete understanding of writing programs to draw pictures. Time for our first exam!

Here’s the “exam” I assigned to the students in my class this week. It’s due in class next week. Don’t worry too much about it; the point is more to go back and review before we move on… we’re not failing anyone!

Instructions

This is what they are working on from now until next week, as a final bit of practice with pictures before we move on to animations.

Pick one of the following four pictures. Write a program that draws a simplification of the picture on that page. Write the program using top-down design, in the way we talked about earlier. As a rule of thumb, divide the overall picture into at least three pieces, and divide each of those into about two to four pieces each. Part of the assignment is to pick out how to divide the picture into pieces, which details are important and which you can leave out. Don’t try to draw everything in the picture. Use each of the following at least once in your picture:

A circle



A rectangle



A line or polygon (one or the other is fine)



Translate, rotate, and scale



Colors (pick whichever seem best)



Comments where appropriate to explain what you’re doing.

Remember: The goal isn’t just to get the computer to draw your picture. It’s also to write a program that is easy to read and understand, looks clean and organized, and explains your picture well. Be a good communicator.

About These Blog Posts

Okay, so it’s become clear that I am sometimes going to need the weekend to work on writing down what we do in class at length. So, from now on, I’m going to stop calling this “late” and just say that I’ll plan on getting the blog post done by the end of the weekend. I’m just changing the definition of “late” so that I’m not late any more. Very clever, isn’t it?

Until next week, have fun, and feel free to ask questions in the blog comments.