R — Functions
Defining functions
Functions in R use the function keyword:
greet <- function(name) {
paste("Hello,", name, "!")
}
greet("Ada") # "Hello, Ada !"
Functions are assigned to variables like any other object.
Parameters and arguments
add <- function(a, b) {
return(a + b)
}
add(3, 7) # 10
Parameters are listed in parentheses. R matches arguments by position or name.
Named arguments
greet <- function(name, greeting = "Hello") {
paste(greeting, name, "!")
}
greet("Ada") # "Hello Ada !"
greet("Ada", greeting = "Hey") # "Hey Ada !"
greet(greeting = "Hi", name = "Ada") # "Hi Ada !"
Default values make parameters optional. Named arguments can go in any order.
Return values
# Explicit return
add <- function(a, b) {
return(a + b)
}
# Implicit return — last expression
add <- function(a, b) {
a + b # no return() needed
}
Both work. Use return() for early exits; let the last expression be the implicit return.
Multiple return values
stats <- function(x) {
list(
mean = mean(x),
sd = sd(x),
n = length(x)
)
}
result <- stats(rnorm(100))
result$mean # average
result$sd # standard deviation
Return a list when you need multiple outputs.
... (dot-dot-dot) — variadic arguments
multi_sum <- function(...) {
args <- list(...)
sum(unlist(args))
}
multi_sum(1, 2, 3) # 6
multi_sum(1, 2, 3, 4, 5) # 15
... collects any number of arguments into a list.
Passing functions as arguments
apply_to_each <- function(f, x) {
result <- c()
for (item in x) {
result <- c(result, f(item))
}
result
}
apply_to_each(function(x) x^2, 1:5) # 1 4 9 16 25
apply_to_each(function(x) x + 10, 1:5) # 11 12 13 14 15
Functions are first-class objects in R — you can pass them around like any other value.
Anonymous functions
# Inline function
sapply(1:5, function(x) x^2) # 1 4 9 16 25
# Lambda-style (R 4.1+)
sapply(1:5, \(x) x^2) # 1 4 9 16 25
Anonymous functions are useful when you need a short function temporarily.
Vectorized functions
Write functions that work on vectors automatically:
celsius_to_fahrenheit <- function(celsius) {
celsius * 9/5 + 32
}
celsius_to_fahrenheit(c(0, 20, 37, 100))
# 32 68 98.6 212
No loop needed — the function works on each element because R is vectorized.
Higher-order functions
Functions that operate on other functions:
# sapply — apply function, simplify result
sapply(1:5, function(x) x^2)
# 1 4 9 16 25
# lapply — apply function, return list
lapply(1:5, function(x) x^2)
# list(1, 4, 9, 16, 25)
# apply — apply function to rows/columns of a matrix
m <- matrix(1:12, nrow = 3)
apply(m, 1, sum) # row sums
apply(m, 2, mean) # column means
# tapply — apply function by group
tapply(mtcars$mpg, mtcars$cyl, mean)
# Reduce — collapse to single value
reduce(1:5, function(a, b) a + b) # 15
Scope and closures
make_counter <- function() {
count <- 0
function() {
count <<- count + 1
count
}
}
counter <- make_counter()
counter() # 1
counter() # 2
counter() # 3
The inner function "remembers" count from its enclosing scope. <<- modifies the enclosing environment's variable.
Documenting functions
calculate_bmi <- function(weight, height) {
#' Calculate Body Mass Index (BMI)
#'
#' @param weight Weight in kilograms
#' @param height Height in meters
#' @return BMI as a numeric value
#' @examples
#' calculate_bmi(70, 1.75)
weight / (height^2)
}
Roxygen comments (#') generate documentation with devtools::document().
Error handling
safe_divide <- function(a, b) {
if (b == 0) {
stop("Cannot divide by zero")
}
a / b
}
tryCatch(
safe_divide(10, 0),
error = function(e) {
cat("Error:", e$message, "\n")
}
)
stop() raises an error. tryCatch() catches errors gracefully.
Recursion
factorial <- function(n) {
if (n <= 1) return(1)
n * factorial(n - 1)
}
factorial(5) # 120
fibonacci <- function(n) {
if (n <= 1) return(n)
fibonacci(n - 1) + fibonacci(n - 2)
}
sapply(0:10, fibonacci) # 0 1 1 2 3 5 8 13 21 34 55
R supports recursion but doesn't optimize tail calls. For deep recursion, use iterative approaches.
Mini Practice
- Write a function that takes a vector and returns its mean, median, and standard deviation as a list
- Create a function with default parameters for a personalized greeting
- Write a vectorized function that converts temperatures from Celsius to Fahrenheit
- Use
sapply()to apply your function to a sequence of values - Write a recursive function that calculates the nth Fibonacci number
Next: conditionals — if, else, and switch →
Related Topics
Frequently Asked Questions about Functions
What is Functions in R?
Functions is a fundamental concept in R. This lesson explains it step by step with clear examples, making it easy for beginners to understand.
How do I learn Functions?
Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Functions.
Why is Functions important in R?
Functions is essential for R development. Understanding this concept will help you write better code and solve real-world problems more effectively.