Introduction to Functional Programming

(Sections 14.1 - 14.2)

The Functional Programming Paradigm

Programming Paradigms

Programming Paradigm

A programming paradigm is a way to describe some of the features of programming languages.


Often a paradigm includes principles concerning the use of these features, or embodies a view that these features have special importance and utility in good programming practice.

Procedural Programming

Procedural Programming

A programming paradigm that solves problems with programs that can be broken up into collections of variables, data structures and procedures.


This paradigm tends to draw a sharp distinction between variables and data structures on the one hand and procedures on the other.

So far we have worked mostly with a procedural paradigm.

Functional Programming

Procedural Programming

A programming paradigm that stresses the central role of functions.

Basic Principles of Functional Programming

  • Computation consists in the evaluation of functions.
  • Functions are first-class citizens in the language.
  • Functions should only return values; they should not produce side-effects.
  • As much as possible, procedures should be written in terms of function calls.

What About R?

R is not a “pure” functional programming language, but it provides a lot of support for the functional programming paradigm.

Let’s examine the basic ideas of functional programming, as they appear in R.

Computation as the Evaluation of Function Calls

In R, functions are Everywhere!

speeds <- bcscr::m111survey[, "fastest"]

There are actually three function calls involved in the above code!

Assignment

The assignment operator <- is actually a function in disguise:

`<-`(variable, value)

Example:

`<-`("a", 5)

Really?

result <- a <- 5
result
[1] 5

<- returns the assigned value (invisibly).

Sub-Setting

The sub-setting operator [ is actually a function in disguise:

people <- c("Dorothy", "Toto", "Scarecrow")
`[`(people, c(2, 3))
[1] "Toto"      "Scarecrow"

Double-Colon Operator

The double-colon operator is also a function in disguise:

`::`(pkg = "bcscr", name = "m111survey")

So Really …

speeds <- bcscr::m111survey[, "fastest"]

can be re-written as:

`<-`("speeds", `[`(`::`("bcscr", "m111survey"), , "fastest"))

Ugh! But is shows that in R almost everything that happens is the result of a function call.

Functions as First-Class Citizens

First-Class Citizens

In programming parlance, a first-class citizen is “entity which supports all the operations generally available to other entities” (see Wikipedia).

Functions in R can:

  • bound to names;
  • appear as elements of a list;
  • appear as arguments in calls to other functions;
  • be returned as the value of a function call.

Appearing in Lists

f <- function(x) x + 3
lst <- list(is.numeric, f)
lst
[[1]]
function (x)  .Primitive("is.numeric")

[[2]]
function(x) x + 3

Arguments in Calls, Returned as Result

cuber <- function(f) {
  g <- function(x) f(x)^3
  g
}
h <- cuber(abs)
h(-2)  # returns |-2|^3 = 2^3 = 8
[1] 8
m <- cuber(function(x) x^2)
m(-2)   # returns ((-2)^2)^3 = 2^6
[1] 64

Avoiding Side-Effects

Side-Effects

Recall that any external result produced by a function (other than what the function returns) is called a side-effect of the function.

In the following call, a name-value pair (a and 5) is added to the Global Environment:

a <- 5  

In the following call there is output to the Console:

cat("Hello!")
Hello!

Avoiding Side-Effects

In R we can’t avoid side-effects entirely if we want our programs to do something practical.

But we try to minimize them by having the function return needed information, as much as possible.

Procedures Written in Terms of Function Calls

Work Declaratively

We will try to accomplish tasks with a small sequence of carefully-defined functions, so that calls to these functions explain by themselves what is going on.

In particular, calls to higher-order functions will replace loops, to a large extent.