Functional Programming:
Quick Start

Adam Berry
Wolfram Research
training@wolfram.com

Everything is an Expression

Basic Structure

An expression consists of a head, and then a sequence of elements.

Head[(Subscript[elem, 1]),(Subscript[elem, 2]),(Subscript[elem, 3]),…]

Operators as Shorthand

All operators in Mathematica are shorthand for an expression. Using the function FullForm we can see how + is interpreted.

FullForm[a+b]

Really Everything, Documents and More

Even this presentation is actually an expression. Documents have head Notebook and then the cells are all Cell expressions. This means that once you know how to work with expressions, you are able to work with everything within the Mathematica system.

Evaluation of Expressions

Standard Evaluation

Evaluation is the core operation done by Mathematica. It will attempt to evaluate expressions based on all definitions it knows.

If we return to our simple example, no additional definitions are known.

a+b

But if we set the variables to an integer,

a=2

a+b

Now we see that the definition for a has been used, so we do the same for b.

b=5

a+b

Now that we see all definitions are used, and we get the result as an output.

This application of definitions is done with infinite recursion, and the results propagate back up through the evaluation.

Modifying Evaluation

The standard evaluation model can also be altered, most commonly with what we call attributes. The simplest example is when using a function like Plot.

Plot[Sin[x],{x,0,2π}]

Attributes[Plot]

So we see that Plot has the attribute HoldAll which prevents normal evaluation of all its elements.

Lists, the Functional Workhorse

Lists are Mathematica’s arrays; as in most programming environments many operations come down to manipulation of these data structures.

Lists (and in fact all expressions in Mathematica) are 1-indexed; using negative indexes will start counting from the end of the list.

Constructing

There are a number of functions for building lists in Mathematica, most commonly used are Table and Range.

Range is really for generating lists of numbers, Table is for lists of more arbitrary expressions.

Range[10]

Table[Expand[(x+y)^i],{i,1,5}]

Manipulation and Extraction

The Part function (operator is list[[i]] ) is the most common way to extract parts of a list.

ls=Range[10]

ls[[3]]

There is also a span operator.

ls[[2;;6]]

Along with Part there are a number of other functions designed for extraction of parts and elements of lists, these include: First, Last, Most, Rest, and Take.

Procedural to Functional Programming

Mathematica is a multi-paradigm language, and while procedural programming is supported, it is better to use the system’s native paradigm.

Lose the Loop

We’ve already seen that there are specific functions for creating lists, but its common for people to use a procedural approach to this.

a={};
Do[a=Append[a,i],{i,1,10}]

a

But when we compare for a larger list, we see a big performance penalty.

a={};
Do[a=Append[a,i],{i,1,20000}];//Timing

Range[20000];//Timing

The same story plays out when we want to do operations on a list.

Length[a]

b={};
Do[b=Append[b,a[[i]]^2],{i,Length[a]}];//Timing

If we use the Map function this simply becomes, and runs much faster.

c=Map[#^2&,a];//Timing

We can do even better, when we realize that this kind of operation is in fact a list construction problem, so if we reframe using Table, we skip the whole need for two lists, and just construct one thing.

d=Table[i^2,{i,20000}];//Timing

The same kind of reframing of a problem can be done with For loops as well.

Conditional Programming

The classic conditional constructs are all supported in Mathematica, but as with loops, they can be reframed into a functional form.

First we will set a test list.

ls=Range[1000000];

Now if we wanted to square only the even numbers in this list we could create a function, and then test this function.

square1[n_]:=If[EvenQ[n],n^2]

square1/@ls;//Timing

We can also use a conditional statement

square2[n_]:=n^2/;EvenQ[n]

square2/@ls;//Timing

The third way that we could write this would be to use a predicate on the argument.

square3[n_?EvenQ]:=n^2

square3/@ls;//Timing

This clearly has the performance advantage, but it also is the easiest code to read and understand. You know just at a glance that the body will only be executed if the input is even.

A similar approach could be used to replace a Which statement, which would just result in several definitions to your symbol.

oddCubeEvenSquare1[n_]:=Which[EvenQ[n],n^2,OddQ[n],n^3]

oddCubeEvenSquare1/@ls;//Timing

oddCubeEvenSquare2[n_?EvenQ]:=n^2;
oddCubeEvenSquare2[n_?OddQ]:=n^3;

oddCubeEvenSquare2/@ls;//Timing

So we see the same advantage in both speed and readability of this code. This second form also makes debugging much easier.

Patterns and Rules

Patterns are a way to represent classes of expressions, can also be thought of as a way to symbolically describe a type of expression.

Extracting Parts with Patterns

The simplest test is to look at the head of an expression; here we can extract the integers.

Cases[{3,4,x,x^2,x^3},_Integer]

Next we can look at expressions that contain powers of x.

Cases[{3,4,x,x^2,x^3},x^_]

FullForm[{3,4,x,x^2,x^3}]

Related functions to Cases are Position, Count, and Select.

Transforming Expressions with Rules

Rules allow you to actually change something that matches a certain pattern; here we modify the above example to extract the actual power.

Cases[{3,4,x,x^2,x^3},x^power_->power]

More powerful is the ability to do this in place in the original expression or list. For that we use the function ReplaceAll in its short form.

{3,4,x,x^2,x^3}/.x^power_->power

Patterns and Functions

We already saw using patterns in function definitions when we were looking at conditionals.

square1[n_]:=If[EvenQ[n],n^2]

Means square1 with one expression as an argument, we could easily add more.

square1[n_,m_]:=n^2+m^2

This allows the same function name to be overloaded for many different types of input.

Patterns extend along with expressions, so there really is no limit to what you can match with a pattern.