NICTA functional programming course

June 14, 2015

These are my notes from working through the NICTA functional programming course material.

Setup

Don't forget to initialize that Cabal sandbox before doing anything else:

$ cabal sandbox init

Development flow

Let's start at the start. We'll work on List.hs, adding the necessary code to make its tests pass.

Open one terminal, and run triggered testing on List.hs. If needed, add fswatch to ~/.bashrc first:

.bashrc:

function fswatch() {
  while [ TRUE ]
  do
    eval "$@"
    echo
    echo "Watching files for changes..."
    inotifywait --exclude '\.git/.*' -e modify -e close_write -e moved_to \
                -e moved_from -e move -e move_self -e create -e delete    \
                -e delete_self -e unmount -qqr .
  done
}

Terminal:

$ fswatch doctest -isrc -Wall -fno-warn-type-defaults src/Course/List.hs

Open another terminal, fire up vi, and edit List.hs. Find an instance of error "todo: ..., make some edits, save the file, and watch the results of the automatically-triggered doctest run. Repeat until the tests pass.

List

A lot of the functions follow the following pattern:

foo Nil = Z
foo (h :. t) = h P foo t

For some value Z and some operator P. For example:

product :: List Int -> Int
product Nil = 1
product (h :. t) = h * product t

In product, Z is 1 and P is *.

sum :: List Int -> Int
sum Nil = 0
sum (h :. t) = h + sum t

In sum, Z is 0 and P is +.

map :: (a -> b) -> List a -> List b
map f Nil = Nil
map f (h :. t) = f h :. map f t

In map, Z is Nil and P is :.. Additionally, h and t are run through f before passing them along.

In all these cases, there is a "zero value" that corresponds to the empty list, and a "combination operator" that combines processed values in some way.

It would be nice if there were an abstraction that we could use to specify just these two properties, and have the rest taken care of for us.

I predict we'll revisit this when we get to Monoid.

flatMap

It's pretty neat that flatten is the same as flatMap id.

seqOptional

I need to be able to reverse a list on that last line:

seqOptional :: List (Optional a) -> Optional (List a)
seqOptional = seqOptional' Nil where
  seqOptional' :: List a -> List (Optional a) -> Optional (List a)
  seqOptional' acc Nil = Full acc
  seqOptional' _ (Empty :. _) = Empty
  seqOptional' acc (Full h :. t) = seqOptional' (acc ++ (h :. Nil)) t

reverse

This is a pretty clever way to do reverse:

reverse :: List a -> List a
reverse = foldLeft (flip (:.)) Nil