Writing Custom Functions in R

In this article, you will learn how to write your own functions in R. Specifically, we will cover:

  1. How to write a simple function
  2. How to write a more complex function
  3. How to write an anonymous function
  4. How to write a function with an unfixed number of arguments
  5. How to write a recursive function

1. Writing a simple function

Let’s define a new function divide that takes 2 arguments a and b and returns a / b:

divide = function(a, b) {
  a / b
}

# divide(1, 1) returns: 1
# divide(1,2) returns: 0.5
# divide(a = 1, b = 2) also returns: 0.5

Normally, a function returns the last expression written inside the curly braces: { }. (In our example above, the last written expression inside the function is: a / b)

If you want, you can choose to return another value by using return(). This will force the function to stop and return the expression inside of return().

For example:

divide = function(a, b) {
  return(a - b) # stop and return a - b
  a / b # this line will be ignored
}

# divide(1, 1) returns: 0
# divide(1,2) returns: -1

2. Writing a more complex function

We can expand our function to check whether the user’s inputs are numbers; If not, the function should return an error message.

We can return error messages by using stop():

divide = function(a, b) {

  # checking if a or b are not numeric values
  if (!is.numeric(a) || !is.numeric(b)) {
    stop("The function expects numeric values")
  }

  else {
    a / b
  }
}

# divide(1, 'x') returns: Error in divide(1, "x") : The function expects numeric values
# divide(1, 1) returns: 1
# divide(1,2) returns: 0.5

Our function still has a obvious problem:

The current version of divide outputs Inf when we divide by zero.

divide(1, 0)

# outputs: Inf

So, we can use warning() to return a warning message when the users tries to divide by zero.

Note that here we are returning a warning not an error because the division by zero can be executed (after all, R does return an answer: Inf), but the answer may not be anticipated by the user.

divide = function(a, b) {

  # checking if a or b are not numeric values
  if (!is.numeric(a) || !is.numeric(b)) {
    stop("The function expects numeric values")
  }

  # if b is 0, return an error message
  else if (b == 0) {
    warning("Division by zero")
  }

  else {
    a / b
  }
}

# divide(3, 0) outputs: Warning message:
# In divide(1, 0) : Division by zero

3. Writing an anonymous function

An anonymous function provides a shortcut to write a simple function. Since the anonymous function has no name, it cannot be referenced/used elsewhere in the code.

The syntax is:

function(input) output

For example:

sapply(c(1,2,3), function(x) 1/x)

# sapply applies the anonymous function to c(1,2,3)
# and outputs: 1.0000000 0.5000000 0.3333333

But, we still have a problem when we divide by zero:

sapply(c(1,2,3,0), function(x) 1/x)

# outputs: 1.0000000 0.5000000 0.3333333 Inf

So, we can include an if-else statement inside the anonymous function to handle division by zero as follows:

sapply(c(1,2,3,0), function(x) {if (x != 0) 1/x else NA})

# outputs: 1.0000000 0.5000000 0.3333333 NA

4. Writing a function with an unfixed number of arguments

We can use the 3 dots to specify that a function takes an undetermined number of arguments.

For example:

add = function(...) {
  sum(...)
}

# add(1,2,3) returns: 6
# which is: 1 + 2 + 3

You can pass the “…” argument to another function inside of your function.

For example:

random.plot = function(n_points, ...) {
  x = 1:n_points
  y = rnorm(n_points)
  plot(x, y, ...)
}

set.seed(1)
random.plot(100)

Output:

So when we specify col = “red”, it will be passed to the function plot inside of our custom function:

set.seed(1)
random.plot(100, col = 'red')

Output:

5. Writing a recursive function

A recursive function is a function that calls itself (i.e. defined in terms of itself).

For example:

factorial = function(n) {

  # if n is 0 or 1, the answer is 1
  if (n == 0 || n == 1) {
    return(1) # done
  }

  # else the function will continue calling itself
  # each time with a smaller n,
  # until we get to n = 1
  else {
    return(n * factorial(n-1)) # recursive call
  }
}

# factorial(3) outputs: 6

Here’s an illustration that represents how the function works when we call factorial(3):

How recursive functions work

Further reading