Chance Coble

Functional Programming in Austin, Texas

First Class Functions :1 Fold, Map, Iter

Posted by Chance Coble on December 18, 2007

Note: I am primarily presenting these 3 articles in F#. The main reason for this is that I am being asked about F# a great deal lately. The same principles of higher order functions will apply to other languages (like OCaml and Haskell). Also, the #light directive is used on all of the following code. You can use this yourself by placing #light at the top of your code files, or type #light into the interactive shell before entering any code. This indicates to the compiler that the code should be parsed by indentation (and thus whitespace should not be ignored) :End Note

Last time we transformed an imperative program into its functional counterpart. In the process we found some patterns we were able to extract to maximize the generality of our approach. Namely, higher order functions like the combinator fold were found to be valuable. In this post, we will take a look at three combinators – iter, map and fold – in order to gain a better understanding of their broad applicability. And it is broad. An entire tutorial could have been dedicated to the surprising capabilities of the fold combinator alone. Again, all of the F# code below can be plugged into an interactive session.

Iter

First let’s look at the iter combinator. It is very simple, it takes as arguments a function which takes an element and returns unit (unit being no meaningful result), and it takes the list/array/seq as its final argument.

Now let’s create something with iter. I will create a simple windows form, and include a list on it. We will use a List type for this, but thanks to the inclusion of iter in libraries with Arrays and Seq types we could have used those as well. That opens up possibilities like applying it to recordsets, files and a number of other .Net objects easily.

#light
open System.Windows.Forms

// Create the names list
let names = ["Arthur Dent";"Ford Prefect";"Slartibartfast"]

// The list control
let listControl =
  // Create the ListBox()
  let dlist = new ListBox()
  // Iterate through the names list, adding each one to the box using "iter"
  List.iter (fun n -> ignore (dlist.Items.Add(n)) ) names
  // return the list box  (which will bind it as the value of listControl
  dlist

// Create a form, add the list box control, set the location and show the form

let form = new Form(Text = "List Manipulation",Height=400,Width=400)
let namebox = listControl
form.Controls.Add(namebox)
namebox.Location <- new System.Drawing.Point(10,10)

// For interactive session
do form.Show()

Our form above first opens the Windows.Forms namespace. It then creates a list called names. It declares the listControl which iterates over the names list. The form value creates the form with its controls and then the Show method is called. The focus here is on the List.iter call in listControl. The first argument is a function (an anonymous function created with the fun notation – also sometimes called a lambda expression). The anonymous function takes an argument and adds it to the list control. The result of the Add call is passed to ignore, which takes any type and returns unit. This is done because our lambda expression has to return unit (but ListBox.Items.Add actually returns something). The final argument is the names list.There is also a version of iter which will include the index of the element it is acting on called iteri. We will not dive into this, but we will be using this type of function when we create something with map.

Map

map is similar to iter in that it takes a function and applies it to every element of a list/array/seq. However map is expected to return something meaningful. It is expected to return a value that replaces the current element in the new list, which map returns. As a quick example, if I had an array of integers and wanted to increase each element of the array by one I could write

> Array.map ((+) 1) [|1;2;3|]

In F# interactive mode the following would be returned

 val it : int array = [|2; 3; 4|]

Let’s use our new found combinator to add something to our form. In this case I will use the mapi combinator (the modified map which accepts an integer representing the location the current element is in the list). I will use map to enumerate each of the names, and then write that to the list using iter. This represents a very powerful aspect of these combinators, using them in combination! The full listing now with map is below. The call to map is now the second let expression in the listControl function. Like iter, it uses an anonymous function and then passes the names list to it. The resulting list (enumlist) is then used in the call to iter.

#light
open System.Windows.Forms

// Create the names list
let names = ["Arthur Dent";"Ford Prefect";"Slartibartfast"]

// The list control
let listControl =
  // Create the ListBox()
  let dlist = new ListBox()
  // map the list into an enumerated list
  let enumlist = List.mapi (fun i n -> i.ToString() + ": " + n) names
  // Iterate through the names list, adding each one to the box using "iter"
  List.iter (fun n -> ignore (dlist.Items.Add(n)) ) enumlist
  // return the list box  (which will bind it as the value of listControl
  dlist

// Create a form, add the list box control, set the location and show the form

let form = new Form(Text = "List Manipulation",Height=400,Width=400)
let namebox = listControl
form.Controls.Add(namebox)
namebox.Location <- new System.Drawing.Point(10,10)

// For interactive Session
do form.Show()

Fold

Fold has a number of implementations, but before getting into that let’s just introduce its basic purpose. Fold applies a function to each element of a list while keeping an accumulating argument. At the point the entire list has been traversed fold returns the accumulated argument. The simplest example I can imagine is summation.
Note, the function in this form doesn’t exist by default in F# … I will explain the F# version shortly.
fold \enspace (+) \enspace 0 \enspace [|1;2;3|] This would return6
To make it painfully simple, the reduction steps that you can imagine for the above calculation are …

fold \enspace (+) \enspace 0 \enspace [|1;2;3|]
\equiv
fold \enspace (+) \enspace 1 \enspace [|2;3|]
\equiv
fold \enspace (+) \enspace 3 \enspace [|3|]
\equiv
fold \enspace (+) \enspace 6 \enspace [||]
\equiv
6

Let’s look at an application of fold in a language (like F#). There are two directions from which you can fold a list. For example, fold_left folds the list starting with the left most element and fold_right folds the list starting from the right most element. This would matter if the computation you were using did not commute (unlike + which we will use in most of our examples for simplicity).

Let’s see what it looks like to calculate the mean of an integer list using fold_left.


let mean () =
     let eventspace = [for i in 10 .. 10 .. 100 -> i *i]
     let sum = List.fold_left (+) 0 eventspace
     let size  = float (List.length eventspace)
     (float sum) / size

Now, let’s get back to our form example. We created a list, we enumerated everyone’s name with mapi and then we used iter to write the names to the list. Now let’s compute something for fold. As an example, we will grab the longest name and write it to a label.

#light

open System.Windows.Forms

open System.Drawing

let names = ["Arthur Dent"; "Ford Prefect"; "Slartibartfast"]

let listControl =
  let dlist = new ListBox()
  let enumlist = List.mapi (fun i n -> i.ToString() + ": " + n) names
  List.iter (fun n-> ignore (dlist.Items.Add(n))) enumlist
  dlist

let form = new Form(Text = "List Manipulation",Height=400,Width=400)
let label = new Label()
label.Text <- "The longest name is: " +
  (names |>
   List.fold1_left (fun name cand -> if(name.Length>cand.Length) then name else cand))
label.Width <- 200
label.Location <- new Point(150,20)
form.Controls.Add(label)
form.Controls.Add(listControl)
listControl.Location <- new System.Drawing.Point(10,10)

// Note: For interactive Session
form.Show()

The code added to the form function creates the label. Then the label’s Text attribute is populated with a string and the result of the fold function. Again an anonymous function is used which checks the length of two strings and returns the longest one.The final form looks like:

hofform.jpg

While this only a very basic introduction, hopefully you will be able to use higher order functions in basic processing tasks at this point. If your experience is anything like mine,
in time you will be using them to compose very powerful abstractions of your programs. At an advanced level they even allow you to create APIs that look more like little languages than a series of method calls. I frequently use combinators in this way, as well as to parameterize the context of large computations. Next time I will address some simple approaches to concurrency using higher order functions.

One Response to “First Class Functions :1 Fold, Map, Iter”

  1. Chance, i have recently begun looking into f# and functional programming as a whole. thanks for posting these nifty explanations and such. keep them coming! –jp

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>