Functions in R

Semillero de R
2016

Function

function

Quiz

quiz

Questions

1) What are the three components of a function?

2) What does the following code return?

y <- 10
f1 <- function(x) {
  function() {
    x +10
    }
  }
f1(1)()

Questions

3) How would you more typically write this code? +(1,*(2,3))

4) Does the following function throw an error when called? Why/why not?

f2 <- function(a, b) {
  a * 10
}
f2(10, stop("This is an error!"))

5) What is an infix function?

How to create a function?

When you need to create a function you should take clear:

  1. The outputs
  2. The inputs
  3. The operations

function

Structure of a function

myfunction <- function(arg1, arg2, arg3, ...) {
  line 1
  line 2
  line 3
  .
  .
  .
}

Example

Create a function, called f1, which adds a pair of numbers.

f1 <- function(x, y) {
  x + y
}

Or

f1 <- function(x, y) {
  return(x + y)
}

Explicitly calling return in a function or not?

Functions with several results

If we have a function which performs multiple tasks and therefore has multiple results to report then we have to include a return statement with c() or list() inside the function is order to see all the results.

Functions with several results

f2 <- function(x, y) {
 z1 <- 2*x + y
 z2 <- x + 2*y
 z3 <- 2*x + 2*y
 z4 <- x/y
 return(c(z1, z2, z3, z4))
}
f2 <- function(x, y) {
 z1 <- 2*x + y
 z2 <- x + 2*y
 z3 <- 2*x + 2*y
 z4 <- x/y
 return(list(z1, z2, z3, z4))
}

Function components

All R functions have three parts:

  • the body(): the code inside the function.
  • the formals(): the list of arguments which controls how you can call the function.
  • the environment(): the “map” of the location of the function's variables.

Example

f <- function(x) x^2
f(3)
[1] 9

Example

formals(f)
$x
body(f)
x^2
environment(f)
<environment: R_GlobalEnv>

formals function

formals(f) <- alist(x=5)
f()
[1] 25

body function

body(f) <- expression(x^3+100)
f(3)
[1] 127

Name masking

Predict the output of the following functions.

Ensure that your workspace is empty, use rm(list=ls()).

Name masking, example

f <- function() {
  x <- 1
  y <- 2
  c(x, y)
}

f()

rm(f)

Name masking, example

If a name isn't defined inside a function, R will look one level up.

x <- 2
y <- 500

g <- function() {
  y <- 1
  c(x, y)
}

g()

rm(x, g)

Name masking, example

The same rules apply if a function is defined inside another function.

x <- 1
y <- 100
h <- function() {
  y <- 2
  i <- function() {
    z <- 3
    c(x, y, z)
  }
  i()
}
h()
rm(x, h)

Name masking, example

The same rules apply to closures, functions created by other functions. What do you think this function will return when we call it?

j <- function(x) {
  y <- 2
  function() {
    c(x, y)
  }
}
k <- j(1)
k()
rm(j, k)

Functions vs variables

The same principles apply regardless of the type of associated value - finding functions works exactly the same way as finding variables:

l <- function(x) x + 1

m <- function() {
  l <- function(x) x * 2
  l(10)
}

m()

rm(l, m)

Functions vs variables

In the following example n takes on a different value depending on whether R is looking for a function or a variable.

n <- function(x) x / 2

o <- function() {
  n <- 10
  n(n)
}

o()

rm(n, o)

Functions vs variables

What happens to the values in between invocations of a function? What will happen the first time you run this function? What will happen the second time?

j <- function() {
  if (! exists("a")) {
    a <- 1
  } else {
    a <- a + 1
  }
print(a)
}

j()
j()

Functions vs variables

and now?

a <- 50

j()
j()

rm(list=ls())

Don't use the operator <<-

A global assignment can be performed with <<-.

If you think you need <<-, think again.

x <- 1
y <- 2
fun <- function () {
    x <- 101
    y <<- 102
}
fun()
x
y

Calling functions

When calling a function you can specify arguments

  • by position,
  • by complete name,
  • or by partial name.

Arguments are matched first by exact name (perfect matching), then by prefix matching, and finally by position.

Example

Consider the next function:

f <- function(abcdef, bcde1, bcde2) {
list(a = abcdef, b1 = bcde1, b2 = bcde2)
}

str(f(1, 2, 3))
List of 3
 $ a : num 1
 $ b1: num 2
 $ b2: num 3

Example

Consider the next function:

f <- function(abcdef, bcde1, bcde2) {
list(a = abcdef, b1 = bcde1, b2 = bcde2)
}

str(f(2, 3, abcdef = 1))
List of 3
 $ a : num 1
 $ b1: num 2
 $ b2: num 3

Example

Consider the next function:

f <- function(abcdef, bcde1, bcde2) {
list(a = abcdef, b1 = bcde1, b2 = bcde2)
}

str(f(2, 3, a = 1))
List of 3
 $ a : num 1
 $ b1: num 2
 $ b2: num 3

Example

Consider the next function:

f <- function(abcdef, bcde1, bcde2) {
list(a = abcdef, b1 = bcde1, b2 = bcde2)
}

str(f(1, 3, b = 1))

Calling a function given a list of arguments

suma <- function(a, b) a + b

argumentos <- list(a=15, b=5)

do.call(suma, argumentos)
[1] 20

Default and missing arguments

f <- function(a = 1, b = 2) {
  c(a, b)
}

f()
[1] 1 2

Arguments in R are evaluated lazily

g <- function(a = 1, b = a * 2) {
  c(a, b)
}

g()

g(10)

Arguments in R are evaluated lazily

myhist <- function(x, breaks=length(x)) {
  breaks
}

myhist(runif(10))

myhist(runif(10), breaks=501)

Infix functions

Most functions in R are “prefix” operators: the name of the function comes before the arguments.

x <- rnorm(n=1000)
y <- runif(n=1000)
cor(x, y)

Infix functions

  • You can also create infix functions where the function name comes in between its arguments, like + or -.

  • All user created infix functions must start and end with %.

  • R comes with the following infix functions predefined: %%, %*%, %/%, %in%, %o%, %x%.

  • The complete list of built-in infix operators that don't need % is: ::, :::, $, @, , *, /, +, -, >, >=, <, <=, ==, !=, !, &, &&, |, ||, ~, <-, <<-.

Example of infix functions

'%+%' <- function(a, b) paste(b, a, sep = " ")

"new" %+% "string"
[1] "string new"
"hello" %+% "my" %+% "world"
[1] "world my hello"

Using infix functions as prefix operators

'%+%'('my', 'life')

'%+%'('my', 'life', 'is', 'better')
# Why you obtain an error?

How can you use the infix - as prefix.

'-'(10, 2)
[1] 8

References

We recommend this references.

  1. http://www.ats.ucla.edu/stat/r/library/intro_function.htm
  2. Wickham, H. (2015). “Advanced R”, Taylor & Francis Group.
  3. Burns, P. (2011). “The R Inferno”, available in http://www.burns-stat.com/pages/Tutor/R_inferno.pdf

quiz