Mar 3, 2026

Today

  • Syntax of defining functions
  • Syntax of calling functions (you already know this)
  • Function environments
  • Debugging functions

Elements of defining a function

  • Function name
  • Use of the function function()
  • function arguments (0 to many)
    • specify input
    • how you tell the function to alter behavior
  • the body
    • optional output
    • usually use return()
fun_name<-function(arg1, arg2, etc.){ # Arguments common but not necessary
  new_obj<-do some stuff # stats, data wrangling, etc.
  return(new_obj)
}

A simple wrapper function

list.files()
##  [1] "bag_of_names.png"        "binding.png"            
##  [3] "enclosing.png"           "execution.png"          
##  [5] "parents.png"             "Writing Functions.pdf"  
##  [7] "Writing-Functions_files" "Writing-Functions.html" 
##  [9] "Writing-Functions.md"    "Writing-Functions.Rmd"
list_Rmd<-function(){ # No arguments needed
   list.files(pattern = ".[r|R]md")
}
list_Rmd()
## [1] "Writing-Functions.Rmd"
  • no return() necessary. list.files() knows to print a list of files automatically

Another basic function

ab_fun<-function(x=1:10, slope=1, inter=0){ # Default values pre-specified
  y <- slope*x + inter
  return(y)
}
ab_fun()
##  [1]  1  2  3  4  5  6  7  8  9 10
ab_fun(slope=3)
##  [1]  3  6  9 12 15 18 21 24 27 30
ab_fun(slope=3, inter=100)
##  [1] 103 106 109 112 115 118 121 124 127 130
  • Can override all, some, or none of the defaults

ab_fun(): no default for x

ab_fun<-function(x, slope=1, inter=0){ # Same, but removed default values for x
  y <- slope*x + inter
  return(y)
}
ab_fun()
## Error in `ab_fun()`:
## ! argument "x" is missing, with no default
ab_fun(x=3:5)
## [1] 3 4 5
  • x is required; “must be specified by the user”; “user-defined”

Quick Exercise

Make a function that assigns a user-defined numeric vector to an object, does some math to change the object’s value, and returns the new object. User-defined means that your function must allow the user to input values of their choice.

Remember the necessary components:

  • function name
  • use of the function function()
  • function arguments (0 to many)
  • the body
    • return() output

Define the function

add_five<-function(x=1:10){ #function env
  y<-x+5    #function env
  return(y)
}
add_five
## function (x = 1:10) 
## {
##     y <- x + 5
##     return(y)
## }
  • comments retained

Execute the function

add_five()
##  [1]  6  7  8  9 10 11 12 13 14 15
add_five(1:5)
## [1]  6  7  8  9 10

Function variables disappear

add_five
## function (x = 1:10) 
## {
##     y <- x + 5
##     return(y)
## }
## <bytecode: 0x116691ff8>
add_five(1:5)
## [1]  6  7  8  9 10
exists("y")
## [1] FALSE

Real-world Example: Estimating Fish Surface Area

Radius and length together can be used in the following equation to calculate surface area.

\[ SA=4\pi \cdot \left( \frac{2(l^p \cdot r^p) + (r^p)^2}{3} \right) \]

calc_SA<-function(len, radius, p = 1.6075){ #typically in mm
  SA<-4*pi*((2*(len^p*radius^p) + (radius^p)^2)/3)
  return(SA) # Units out would be mm^2
}
calc_SA(45, 12)
## [1] 219097.8

Environments

  • An imaginary space that holds names that are associated with values stored elsewhere on memory. “Bag of names.”

Function Execution Environments

  • Functions create new, short-lived environments called execution environments
    • object names usually passed into the execution environment
    • variables created in execution environments are not preserved
    • they exist only while the function is in progress

Functions have limited scope

Function Enclosing Environments

An enclosing environment can be thought of as a function’s parent environment. It is where a function was created and where the function’s name is stored. Usually the global environment.

y <- 1
f <- function(x) x + y

Execution Environments

h <- function(x=1) {
  a <- 2
  return(x + a)
}
y <- h(1)
  • Function written, stored on memory, and linked to a name.
  • Execution environment created with y <- h(1)
  • a is assigned to value 2 within the execution environment
  • Addition is performed, then stored as y within the enclosing environment.
  • Execution environment dissapears.

Short-lived execution environments

system.time(add_five(1:10))
##    user  system elapsed 
##       0       0       0
system.time(add_five(1:10^8)) # 100 million values
##    user  system elapsed 
##   0.145   0.088   0.287

Debugging functions with browser()

  • Because variables in the function environment disappear, it can be hard to find problems in functions
  • browser() allows you to:
    • pause execution of the function
    • access objects within the function environment
    • manipulate objects within the function environment
    • continue OR quit function execution
  • The location of browser() within the function matters
add_five<-function(x=10){
  browser()
  y<-x+5
  return(y)
}

  • (Go to Console)

Other debugging tools

base R:

  • stopifnot() - ensures data meets specific conditions before proceeding
  • debug()
  • traceback()

RStudio:

  • an error inspector
  • flag breakpoints in code

packages:

  • debug

Exercise 2 (Maybe a take home)

Write a function to calculate the species richness from each row of a community data matrix (e.g., vegan::dune or vegan::varespec). Richness is defined as simply the number of different species present at each site.

Exercise 2: Calculating Species Richness

library(vegan)
data(dune)
dune[1:5, 1:5]
##   Achimill Agrostol Airaprae Alopgeni Anthodor
## 1        1        0        0        0        0
## 2        3        0        0        2        0
## 3        0        4        0        7        0
## 4        0        8        0        2        0
## 5        2        0        0        0        4

Exercise 2: Calculating Species Richness

data(varespec)
varespec[1:5, 1:5]
##    Callvulg Empenigr Rhodtome Vaccmyrt Vaccviti
## 18     0.55    11.13     0.00     0.00    17.80
## 15     0.67     0.17     0.00     0.35    12.13
## 24     0.10     1.55     0.00     0.00    13.47
## 27     0.00    15.13     2.42     5.92    15.97
## 23     0.00    12.68     0.00     0.00    23.73

Exercise 2: Calculating Species Richness

rich<-function(comm){
  comm[comm > 0]<-1
  rowSums(comm)
}
rich(varespec)
## 18 15 24 27 23 19 22 16 28 13 14 20 25  7  5  6  3  4  2  9 12 10 11 21 
## 29 26 23 25 26 28 27 27 27 31 25 27 30 26 23 24 25 26 19 27 18 24 23 28

Exercise 2: Calculating Species Richness

rich<-function(comm){
  apply(comm > 0, 1, sum)
}
rich(varespec)
## 18 15 24 27 23 19 22 16 28 13 14 20 25  7  5  6  3  4  2  9 12 10 11 21 
## 29 26 23 25 26 28 27 27 27 31 25 27 30 26 23 24 25 26 19 27 18 24 23 28