Haskell for Kids: Week 2!

It’s time for the second weekly roundup from my Haskell programming class for kids! (Here’s a link to last week’s.)

Pictures From Last Week

Remember, last week’s assignment was to write a program to draw an involved picture about something of your choosing. Here are some of the results:

This Week: Organization

The theme for this week is organization. One problem that’s easy to run into quickly in computer programming is that you write computer programs that are so involved and complicated that you get stuck: the program might even work, but it’s so hard to understand that you dread having to change it! We spent some time talking about ways to organize your computer programs to make them easier to read.

Parts of a Program

Just to review, a computer program that you wrote on the first day of class might look like this:

import Graphics.Gloss picture = color red (pictures [ circle 80, translate 50 100 (rectangleSolid 100 50) ])

We looked a little closer at how programs are built during our second class last week. Here are the parts.

Import Statement

The first line is the import statement: remember that’s where we tell the computer that we will be using the Gloss library. If it weren’t for that line, then the computer would have no idea what words like color, red, pictures, circle, and so on actually mean! You only have to import a library once, no matter how many times you use the things that it defines.

Definitions

After the import statement, your program defines some new words, called variables. The one variable we defined in the program earlier was picture. For the moment, we always define a variable called picture, because that’s how the computer knows what to draw. What we didn’t mention in my last post, though, is that you can define other variables besides picture! And when you do, you can use them in the same way you could use circle or other built-in picture types.

For example, look at this program:

import Graphics.Gloss picture = snowman snowman = pictures [ translate 0 ( 50) top, translate 0 ( 0) middle, translate 0 (-75) bottom ] top = circleSolid 50 middle = circleSolid 70 bottom = circleSolid 90

This program defines five variables: picture, snowman, top, middle, and bottom. Again, the computer is only going to draw the thing labeled picture, but the other variables are useful for keeping things organized. There are two important rules here, which are part of the programming language, Haskell:

Each new definition has to start in the left-hand column. It should not be indented. If you start a new line in the same definition, you have to indent it. It doesn’t matter how far, but you need to indent at least a little.

It came up that I’m defining picture first, and then snowman, and so on… some people thought it would make more sense to do it in the other order. That’s fine! The order of your definitions makes no difference at all, so feel free to start with picture and work your way down to the parts (sometimes called “top down”, or to start with the parts and work your way up to the overall picture (sometimes called “bottom up”), in whatever way makes sense to you. You could even put them in alphabetical order. The computer doesn’t care. (I don’t actually recommend alphabetical order… but you could!)

Expressions

The parts after the equal sign (=) in your definitions are called expressions. This is where you say what the variables actually mean. Most of what we looked at last week had to do with the different kinds of expressions you can put there: circles, rectangles, and so on, and even some more complicated expressions involving color or translate and so on.

In our second class last week we said a little bit more about what an expression is. Look at this example:

picture = translate 10 20 (circleSolid 50)

The expression on the right side of the definition of picture has four parts to it, all written next to each other. When you see something like that, the first part is called a function, and then rest of them are called parameters. So here we have:

translate – That’s the function 10 – That’s the first parameter 20 – That’s the second parameter (circleSolid 50) – That whole thing is the third parameter

Pay attention to the parentheses! Parentheses mean “treat this whole part here as just one thing”.

Every function expects a certain number of parameters. For example, translate always expects three: the first is how far to move horizontally, the second is how far to move vertically. The third is the picture that you’re moving. If you tried to give it only 2 parameters, or 5 parameters, it won’t work! (If you want to, try it and see what happens.)

What about the part inside the parentheses? It’s just another expression! Can you identify which part of it is the function, and which are parameters?

There’s one other piece: you might notice that pictures is a bit different. The piece that comes after pictures has square brackets around it, and you can have as many things in there as you like, with commas between them. That’s just another kind of expression, called a list. So far, pictures is the only thing we’ve seen that uses lists, but we’ll see another one soon!

Here’s the whiteboard after we discussed the parts of a program and expressions:

The conversation bubble was a different discussion: we talked about how you can make interesting shapes by drawing in white over the top of another shape.

Some Advice

Most of that was from the second class last week. This week, we spent some time talking about good advice for writing computer programs. We came up with the following:

Be Fanatical about Organization

If you don’t stay organized, it’s just not possible to write interesting computer programs. Your programs should be designed out of pieces, and you should pick those pieces to be meaningful. Here’s an example of what not to write:

import Graphics.Gloss

pictures = [ translate 71 123 (rectangleSolid 30 200), rotate 45 (translate 10 1 (color green (circle 50))), translate 100 100 (scale 2 2 (rectangleWire 10 10)),

… and on, and on, and on …

That’s okay to do when you’re trying things out or playing around. But eventually, you want to break up your program into manageable pieces! A long list of 40 different drawing operations isn’t very fun to read, and it definitely isn’t fun to try to make changes to later on.

Instead, try to do something like the snowman example earlier: the pieces of the snowman are broken down into smaller pieces, so you can think about one thing at a time. Of course, not just any pieces will do! You don’t want one piece to have the grass and one leg and sun, and then then next piece to have another leg and a tree! Try to find pieces of your picture that make sense on their own. Computer programmers even have a fancy word for that: we call those pieces coherent or we say that they have a lot of cohesion.

Earlier, we mentioned the ideas of “top down” and “bottom up” approaches to programming: you can either start by defining picture, and then define its pieces… or you can start by defining the pieces, and then build bigger things out of them. For now, whichever direction you find easier is okay, but just pay attention to which one you’re doing, and maybe taking the opposite approach once in a while will make certain things easier.

Be a Good Communicator

The second piece of advice we talked about is to be a good communicator. You’re not just writing a computer program for the computer to run it: you’re also writing something for other people to read. You might show your programs to other people in the class, or to teachers, or plenty of other people.

A really good way to communicate well is to pick good names for things. If you’re drawing a flower, your program will be a lot easier to understand when your variables are called leaf, stem, and petal; not picture1, picture2, and picture3!

Another tool you can use that’s helpful for communicating well is called comments. The computer will ignore any part of your program that’s between a {- and a matching -}. (That’s an open curly brace following immediately by a dash… and then a dash followed by a closing curly brace.) For shorter comments, the computer will ignore anything from — (two dashes in a row) to the end of the line. So you can write something like this:

{- Picture of my dog, by Chris Smith This is a picture of my dog, Ruby. She is part border collie. -} picture = pictures [ circleSolid 50, -- That's her body rectangleSolid 20 100 -- That's her tail ]

(No, that doesn’t really look much like a dog… gimme a break, it was just a quick example!)

By picking good names and adding comments to explain what you’re doing, you can make your programs a lot easier to read and understand, both for yourself and other people. That’s what we mean by being a good communicator.

Hide Unimportant Ideas

There’s only so much that one person can remember at a time! Because of that, another important idea in computer programming is to hide the stuff that isn’t important, so that you can focus on what is.

We talked about a new language feature that helps here, and that is let and where. Here’s ax example of using where in a program.

import Graphics.Gloss picture = snowman snowman = pictures [ translate 0 ( 50) top, translate 0 ( 0) middle, translate 0 (-75) bottom ] where top = circleSolid 50 middle = circleSolid 70 bottom = circleSolid 90

That is almost the same snowman program as before: but with one difference. The variables top, middle, and bottom are defined after the word where, and still inside the definition of snowman. (It might not be obvious here, but the word where is still indented by a few spaces, so it’s still part of the definition of snowman.

What this does is make top and middle and bottom only mean something inside of the definition of snowman. So you can use them when you’re defining snowman, but if you tried to use them in a different part of your program, it wouldn’t work. The error message you’d get would say “not in scope”.

The idea of scope is important in computer programming. The scope of a variable is how much of the program it can be used in. When you write more involved programs, you don’t want every single variable that you define to be visible everywhere! As this snowman program gets bigger, maybe we might want the same name, like top, to mean something completely different when we’re drawing a different part of the scene. That’s okay, because this top is only “in scope” during the definition of snowman.

We talked about an analogy for this: if you’re in England, it makes perfect sense to say “I saw the queen today!” But, if you’re in the United States, it doesn’t make sense any more, because we don’t have a queen. The phrase “the queen” means something different depending on where you are! So if I talked like the Haskell programming language, and you said to me “I saw the queen today!”, I might say in response, “Not in scope: the queen”.

By the way, here’s the way to write that same snowman program but using let instead of where.

import Graphics.Gloss picture = snowman snowman = let top = circleSolid 50 middle = circleSolid 70 bottom = circleSolid 90 in pictures [ translate 0 ( 50) top, translate 0 ( 0) middle, translate 0 (-75) bottom ]

This means exactly the same thing: you just get the choice between defining the pieces first (that’s let) or defining the pieces afterward (that’s where).

Pay Attention To Details

Finally, the last piece of advice we had for computer programming was to pay close attention to details. There are lots of situations where a normal person might be able to figure out what you want, but your computer program still won’t work if you don’t get all the details right!

We looked at some of these details more closely:

Indentation: You are not allowed to indent the first line of a definition. You must indent every line after that. These are rules in the Haskell programming language; if you don’t follow them, your programs won’t work. Also, if you use let and where, then you have to indent all the definitions there by the same amount.

allowed to indent the first line of a definition. You indent every line after that. These are rules in the Haskell programming language; if you don’t follow them, your programs won’t work. Also, if you use let and where, then you have to indent all the definitions there by the same amount. Parentheses: A lot of people have trouble with this when they get started with programming. (For that matter, most of us still make mistakes with parentheses even when we’ve been programming for years!) You have to match up your opening and closing parentheses, or your program just won’t work.We talked about a few things that help. Some programming tools, including the web site we’re using right now, will help you match up parentheses by pointing them out. Using the web site, try putting your cursor right after a parenthesis: the matching one will have a gray box drawn around it! This can help a lot… but it’s only there if the tool you’re using happens to do it.We also talked about counting parentheses. There’s a trick most programmers figure out for checking their parentheses: start out with the number 0 in your head, and then read through part of your program, and add one every time you see an open parenthesis, and subtract one every time you see a close parenthesis. If everything matches, you’ll end up back at zero at the end! If not, you may need to figure out where you’re missing a parenthesis.

Spelling: If you misspell a word, it won’t work! So paying attention to spelling is important.

Capitalization: Whether words are capitalized or not matters! So, for example, red works fine as a color, but Red doesn’t work! We talked about the convention of capitalizing new words inside a variable name, even through the variable name starts in lower case, like in circleSolid. That has a name: “camel case”… because it’s sort of like upper-case or lower-case, except it has a hump in the middle.

Spaces: Most of the time, you can put spaces in your program however you like: but they often do need to be there! You can’t run together numbers or variable names and expect it to work. A lot of programmers like to use spaces to line things up in nice columns, too.

Here’s our whiteboard at the end of this part:

Paying attention to details like this is very important, and will help a lot as you get more experience with writing programs.

Things Other People Said

We finished up today by reading some quotations by famous people about computer programming, talking about, and did some laughing, too.

Any fool can write programs that a computer can understand. Good programmers write code that humans can understand. – Martin Fowler

This is talking about the importance of being a good communicator, which was one of the points above.

Controlling complexity is the essence of computer programming. – Brian Kernighan

Brian Kernighan was one of two people who invented C, one of the most popular programming languages in the world. He’s talking here about the important of organization, and of hiding unnecessary details, so that you can build programs without being overwhelmed by how complicated everything gets! In fact, he says that’s the most important thing about computer programming.

Any sufficiently advanced bug is indistinguishable from a feature. – Rich Kulawiec

Remember a “bug” is a mistake in your program. A “feature” is something it does, and is supposed to do. I threw this quotation in for Sophia, because on the first day of class, she found a bug in my web site where you could stretch a solid circle and it would accidentally leave a hole in the middle, and she used it to make a mouth as part of her first program. But then the next day, I fixed the bug and broke her program! That’s definitely a bug that turned into a feature.

If you’re about to add a comment, ask yourself, “How can I improve the code so that this comment isn’t needed?” – Steve McConnell

This is a great concept! We talked about using comments to explain what’s happening in your programs: but what’s even better than having a comment is organizing your program so that it’s obvious what you’re doing, and you don’t need the comment any more. This certainly doesn’t mean never write comments: it just means see if you can keep things simple so there’s not as much to explain.

Great software, likewise, requires a fanatical devotion to beauty. If you look inside good software, you find that the parts no one is ever supposed to see are beautiful, too. I’m not claiming I write great software, but I know that when it comes to code, I behave in a way that would make me eligible for prescription drugs if I approached everyday life the same way. It drives me crazy to see code that’s badly indented, or that uses ugly variable names. – Paul Graham

This is Paul Graham being funny, but also making a very good point. This touches on the first and last points of advice earlier.

There are two ways of writing computer programs: One way is to make it so simple that there are obviously no mistakes. The other way is to make it so complicated that there are no obvious mistakes. – C.A.R. Hoare (sort of)

The last one is actually slightly misquoted. I didn’t correct it because the original version means nearly the same thing but uses more technical language.

Your Assignment

Your assignment is to clean up your computer program! Imagine that you’re going to share with other people not just the picture it draws, but the computer program itself. Get it as clean and nice looking as you can: try to break things down in logical ways, pick really good names, fix all the details, and communicate well to people reading your code.

See you next week!