I see my 7-year-old son as someone, who is deeply interested in anything computer related. I recall how he went through photos on my iPod Touch when he was only two years old. Then video games kicked in, and now he can make an 8-hour flight back to Europe without taking a break from a game on an iPad.
This is all nice and cool, but why don't we do something more useful with this passion?! He has been curious about programming, he practiced basic function calls via the game Code Combat. I figured, let's take this to the next level and try programming.
I wanted to use a language that is easy to understand, but can be very powerful. I considered Python or JavaScript, but I figured his first real programming language should be a functional one, and the simple nature of LiSP made Clojure the obvious choice.
I wanted to find an editor that's easy to use. I was aware of LightTable, but I've never tried it. We downloaded it on my wife's 11" MacBook Air and we jumped in.
What's really cool about LightTable is that you don't need to run a separate REPL, you could just write your Clojure expressions in a clj file, save it and by hitting <Cmd> + <Shift> + <Enter> the expressions are evaluated in line, right next to them. It's really the best tool for beginners.
We worked on a rectangular area calculator in our first session, since that's what he's been learning at school. This was our first expression:
(defn area [x y] (* x y)) (area 2 3) # 6We tried different numbers, he was pumped when the correct number was printed in LightTable after the evaluation.
Our area function is for rectangles, but what if we wanted to calculate the square's area? We only had to pass one number to our calculator.
Of course we could have done this:
(area 4 4) # 16But this was not very elegant. I proposed creating a new function for
square-area
and calling area
from that this way:
(defn square-area [x] (area x x)) (square-area [4]) # 16My goal here was to show him how one function can leverage the functionality of another function. He liked this a lot.
In our next session - as he constantly nudged me to continue his journey in Clojure programming land - I wanted to teach him something we could build upon: we learned about vectors, which is similar to Arrays in other programming languages.
We started out with listing his best friends:
(def friends [:andy :james :tommy :ethan :elliot])I explained to him that these names are in order and they will always remain in order the way he defined it first. There are ways to explore the collection, for example pulling the first item from it. This is what we tried:
(first friends) # :andyI asked him if he could get the last item of the vector. He thought about a bit and this is what he came up with:
(last friends) # :elliotExcellent! Then I asked him how we could get the third item from the collection and he intuitively tried the function
third
, which does not exist. I showed him the nth
function to do that. This is what he tried to get the third item:
(nth friends 3) # :ethanBut oh, it returned the fourth and not the third item. So we talked about the 0-based index, which he grasped, but did not make much sense to him.
I told him: "Imagine how great it would be to sort these names in alphabetical order. Do you know what verb would describe that operation?" He said "sort", so we gave it a try:
(sort friends) # (:andy :elliot :ethan :james :tommy)We both smiled at how easy it was. Then I asked him if we could put the names in descending order. We were looking for the right word, and he came up with
backwards
. Well, it's close, so I asked him to look up synonyms for that word in Google. We both settled on reverse
.
He tried this:
(reverse friends) # (:elliot :ethan :tommy :james :andy)Oh-oh. This only put the original list into reverse order without sorting. It was obvious that we needed to sort it first and then reverse it. I helped him to write this:
(reverse (sort friends)) # (:tommny :james :ethan :elliot :andy)
We wrapped up our session by creating a vector with numbers.
(def numbers [9 12 5 7 1])Based on what he learned earlier, he put them numbers in descending order:
(reverse (sort numbers)) # (12 9 7 5 1)I showed him how we could use the
filter
and the odd?
functions to filter out the odd numbers.
(filter odd? numbers) # (9 5 7 1)He was able to sort the odd numbers by using the
sort
function:
(sort (filter odd? numbers)) # (1 5 7 9)Picking the largest odd number was a tricky one, we had to look at the docs, as this did not work:
(max (filter odd? numbers)) # (1 5 7 9)But this did:
(apply max (filter odd? numbers)) # 9There was an easier way to get the largest odd number: reverse sorting the odd numbers and getting the first item. This is what we wrote:
(first (reverse (sort (filter odd? numbers)))) # 9We both smiled when we saw the result.
This is the full code we wrote together:
We are going to spend half of our time going through the same function composition the next time. Then we might look at other collection types like maps and sets. I don't want to push him, but if he asks for it, we'll go as far as we can.