Friday, August 15, 2014

Practising recursion with accumulate, filter and map for deeply nested lists

I'm practising recursion going through some of the exercises in David Evans book Introduction to Computing, Explorations in Language, Logic, and Machines.

These are the solutions to three of those exercises:

  1. An accumulate (reduce) function for a list which can contain arbitrarily deeply nested lists.

  2. A map function for a list which can contain arbitrarily deeply nested lists.

  3. A filter function for a list which can contain arbitrarily deeply nested lists.

You can find these and other exercises and examples from the book in this GitHub repository.

I'm loving the book.

Monday, August 11, 2014

Interesting Talk: "SICP Lecture 2A: Higher-order Procedures"

I've just watched this wonderful class by Gerald Jay Sussman:

Kata: Find indexes of all upper-case letters in a word

Last Friday I went to a kata of Barcelona Software Craftsmanship facilitated by Carlos Blé at Runroom.

We had to write a function using TDD that when given a word will produce an array containing the positions of all the capital letters in the word.

The most interesting part of the exercise came during the second interaction in which we had the constraint of not mutating any value.

Although we didn't managed to finish the exercise, we had a very interesting debate about recursion, baby steps and TDD.

Once back at home I started to grow the code again in tiny steps, trying to make explicit the problem patterns before taking the leap of faith of recursion.

This is the code passing all the tests right before being refactored to be recursive:


In the repetition that existed in this code, it was possible to see two emerging patterns:
  1. The base case of the recursion which happens when the word length is equal to the current index.
  2. The use of concat to make the result grow when the character at the current index is a capital letter
Using that information I refactored the code to get to this recursive solution, (after a pair of failed attempts...):


In it you can still distinguish the similarities with the previous non-recursive version.

The base case now returns an empty array and concat is used again when a capital letter is found at the current index, only that the concatenation is now with a one-element list containing the current index.

In any other case, no element is concatenated to the result and the function is called again with the next index.

Later, I refactored the code and the tests a bit more to get to these final versions of the tests:


and the code:


You can check the code in this GitHub repository.

All in all, I'm under the impression that I wrote the before-recursion code that way because I already had an insight of how the recursive solution was going to be.

Had I written it in a different way, might it have made more difficult to find a recursive solution?
What would have happened with a more difficult problem?

I'm not sure if TDD alone will help me to find recursive solutions.

I will keep working on it.

Sunday, August 10, 2014

Some home-made implementations of map

This post originated in a conversation we had during the last Barcelona Software Craftsmanship event.

We talked about a technique to recursively processing list elements once at a time in which you have to focus on two things:
  1. How to process an empty list (the base case of the recursion)
  2. How to process a non empty list in terms of the result of processing the tail of the list (the list except the first element)
To illustrate it, let's see a possible implementation of map in SML:


It uses the following list functions:
  • hd to extract the head of the list (its first element)
  • tl to extract the tail of the list (the list except the first element)
  • null that returns true if the list is empty and false otherwise
The :: operator adds an element at the beginning of a list.

We can use a similar approach to write map in Racket:


Here the name of the functions are a bit more expressive: first, rest and empty?.
The cons function adds an element at the beginning of a list.

A more idiomatic way to write map in SML would be using pattern matching:


This version is using the same approach but pattern matching makes the code more concise and expressive.

As a bonus here is a beautiful way to append two lists in SML using the same technique and pattern matching:


This is very well explained in the first unit of of the Programming Languages course from Washington University at Coursera that I completed last year.

There is going to be a new edition starting up Oct 2. I cannot recommend it highly enough.