R - Functions
R - Functions
Section titled “R - Functions”A function is a reusable block of code that performs a specific task. In R, functions are first-class objects, meaning you can work with them just like any other variable. Using functions is essential for writing clean, efficient, and maintainable code.
Function Definition
Section titled “Function Definition”You create an R function using the function keyword. The basic syntax is:
function_name <- function(argument_1, argument_2, ...) { # Code to execute (the function body) return_value # The last evaluated expression is returned automatically}Function Components
Section titled “Function Components”- Function Name: The name you use to call the function (e.g.,
function_name). Stored as an object in the R environment. - Arguments: Placeholders for the data you’ll pass into the function. They can have default values, making them optional.
- Function Body: The set of R statements that define what the function does.
- Return Value: The result of the function. In R, the value of the last expression evaluated inside the function is automatically returned. You can also use
return()explicitly.
Best Practice: Pure Functions
Section titled “Best Practice: Pure Functions”A pure function is a function that, for the same input, will always return the same output and has no observable side effects (like printing to the console or modifying a global variable). It’s a best practice to write pure functions whenever possible, as they are easier to test and reason about.
Let’s refactor the original example to follow this principle. Instead of printing the squares inside the loop (a side effect), our function will return a vector of the squared numbers.
# A user-defined function to calculate the squares of a sequence of numbers.# This is a 'pure' function: it returns a value and has no side effects.calculate_squares <- function(n) { # Input validation: check if n is a single positive number if (!is.numeric(n) || length(n) != 1 || n < 1) { stop("Argument 'n' must be a single positive integer.") } # The 'sapply' function is a more idiomatic R way to apply a function over a vector sapply(1:n, function(x) x^2)}
# Call the function and store the resultsquared_numbers <- calculate_squares(6)
# Now, print the result (the side effect is outside the function)print(squared_numbers)When we execute the above code, it produces a clean vector as output:
[1] 1 4 9 16 25 36Calling Functions
Section titled “Calling Functions”Argument Matching: By Position and Name
Section titled “Argument Matching: By Position and Name”You can provide arguments to a function by their position or by explicitly naming them. Naming arguments is often clearer and less error-prone.
# A simple function with multiple argumentscalculate_result <- function(a, b, c) { result <- a * b + c return(result)}
# Call by position (5*3 + 11)print(calculate_result(5, 3, 11))
# Call by name (order doesn't matter)print(calculate_result(c = 3, a = 11, b = 5))This produces the following result:
[1] 26[1] 58Default Arguments
Section titled “Default Arguments”You can provide default values for arguments, making them optional when the function is called.
# A function with default argumentscreate_greeting <- function(name, greeting = "Hello") { paste(greeting, name, sep = ", ")}
# Call the function using the default greetingprint(create_greeting("Alice"))
# Call the function, overriding the defaultprint(create_greeting("Bob", greeting = "Goodbye"))This produces the following result:
[1] "Hello, Alice"[1] "Goodbye, Bob"Modern Usage: The Pipe Operator
Section titled “Modern Usage: The Pipe Operator”The pipe operator, %>% from the magrittr package (or the native |> in R 4.1+), is a powerful tool for making your code more readable. It takes the result of the expression on its left and passes it as the first argument to the function on its right.
library(magrittr) # or library(dplyr)
# Without the pipeprint(round(mean(1:10)))
# With the pipe: reads like a sentence "take 1:10, then find the mean, then round it"1:10 %>% mean() %>% round() %>% print()Both expressions produce the same result, but the piped version is often easier to follow for complex chains of operations.
[1] 6[1] 6Further Learning: Functional Programming
Section titled “Further Learning: Functional Programming”R is a great language for functional programming. The purrr package from the tidyverse provides a complete and consistent set of tools for working with functions and vectors. It’s a great next step after mastering the basics. For example, purrr::map() is a powerful alternative to loops or sapply().