Writing Functions in R: Building Your Own Magic Machines
The Story of Functions
Imagine you have a magic box. You put something in, the box does something special, and out comes a result! That’s exactly what a function is in R.
Think of it like a cookie-making machine:
- You put in ingredients (inputs)
- The machine does its magic (processing)
- Out come delicious cookies (output)
Let’s learn how to build our own magic machines!
Function Definition
What Is It?
A function is a recipe that tells R what to do. You write it once, and use it as many times as you want!
The Magic Formula
my_function <- function() {
# Your magic goes here
}
Your First Function
Let’s make a function that says “Hello!”
say_hello <- function() {
print("Hello, friend!")
}
# Use it!
say_hello()
# Output: "Hello, friend!"
What happened?
- We named our function
say_hello - We used
function()to create it - Inside the curly braces
{}we put our magic - We called it with
say_hello()
Function Arguments
What Are Arguments?
Arguments are ingredients you give to your function. Like telling the cookie machine what flavor to make!
Adding Ingredients
greet <- function(name) {
print(paste("Hello,", name))
}
greet("Emma")
# Output: "Hello, Emma"
greet("Max")
# Output: "Hello, Max"
See the magic? The same function works for different names!
Multiple Arguments
Want more ingredients? Add more!
make_sandwich <- function(bread, filling) {
paste(bread, "with", filling)
}
make_sandwich("Wheat", "Cheese")
# Output: "Wheat with Cheese"
Default and Named Arguments
Default Arguments
What if someone forgets an ingredient? Give it a backup value!
greet <- function(name = "Friend") {
paste("Hello,", name)
}
greet() # "Hello, Friend"
greet("Luna") # "Hello, Luna"
The = "Friend" is the default. If you don’t give a name, R uses “Friend”!
Named Arguments
When you have many ingredients, you can call them by name:
make_cake <- function(flavor, size, layers) {
paste(size, flavor, "cake with",
layers, "layers")
}
# Using names (any order works!)
make_cake(
layers = 3,
flavor = "Chocolate",
size = "Large"
)
# Output: "Large Chocolate cake with 3 layers"
Pro tip: Named arguments let you skip the order!
Return Values
What Comes Out?
Every function can give something back. That’s the return value!
Two Ways to Return
Way 1: The last line (automatic)
add_numbers <- function(a, b) {
a + b # This gets returned!
}
result <- add_numbers(5, 3)
# result is now 8
Way 2: Using return() (explicit)
check_age <- function(age) {
if (age >= 18) {
return("You can vote!")
}
return("Too young to vote")
}
check_age(21) # "You can vote!"
check_age(10) # "Too young to vote"
Returning Multiple Things
Want to return more than one thing? Use a list!
get_stats <- function(numbers) {
list(
total = sum(numbers),
average = mean(numbers),
count = length(numbers)
)
}
stats <- get_stats(c(10, 20, 30))
stats$total # 60
stats$average # 20
Anonymous Functions
Functions Without Names
Sometimes you need a quick, throwaway function. No name needed!
The Old Way
# Without a name
sapply(1:5, function(x) x * 2)
# Output: 2 4 6 8 10
This function(x) x * 2 has no name. It just does its job and disappears!
When to Use Them?
- Quick, one-time operations
- Inside other functions like
sapply,lapply - When naming feels like overkill
# Double every number
numbers <- c(1, 2, 3, 4, 5)
lapply(numbers, function(n) n * 2)
Lambda Functions
The Shortcut Syntax
R 4.1+ introduced the backslash shorthand \(x) for quick functions!
# Old way
function(x) x + 1
# New lambda way (R 4.1+)
\(x) x + 1
Lambda in Action
# Square each number
sapply(1:5, \(x) x^2)
# Output: 1 4 9 16 25
# Filter with lambda
Filter(\(x) x > 3, 1:10)
# Output: 4 5 6 7 8 9 10
Why Use Lambdas?
- Shorter to write
- Cleaner code
- Perfect for simple operations
# Compare:
# Old: sapply(1:5, function(x) x * x)
# New: sapply(1:5, \(x) x * x)
Variadic Arguments
What’s Variadic?
Sometimes you don’t know how many ingredients you’ll get. Use ... (three dots) to accept any number of arguments!
The Magic Dots
add_all <- function(...) {
numbers <- c(...)
sum(numbers)
}
add_all(1, 2) # 3
add_all(1, 2, 3, 4, 5) # 15
add_all(10, 20, 30) # 60
The ... captures everything!
Passing Dots Along
You can pass ... to other functions:
my_paste <- function(...) {
paste(..., sep = " - ")
}
my_paste("Apple", "Banana", "Cherry")
# Output: "Apple - Banana - Cherry"
Mixing Regular and Variadic
greet_all <- function(greeting, ...) {
names <- c(...)
for (name in names) {
print(paste(greeting, name))
}
}
greet_all("Hi", "Emma", "Max", "Luna")
# "Hi Emma"
# "Hi Max"
# "Hi Luna"
Putting It All Together
Here’s a function using everything we learned:
make_report <- function(
title = "Report",
author = "Anonymous",
...
) {
items <- c(...)
header <- paste(title, "by", author)
body <- paste(items, collapse = "\n- ")
return(list(
header = header,
content = paste("- ", body)
))
}
report <- make_report(
title = "Shopping List",
author = "Emma",
"Apples", "Bread", "Milk"
)
We used:
- Default arguments (
title,author) - Named arguments (calling by name)
- Variadic arguments (
...for items) - Return values (the list)
Quick Reference
graph TD A["Function Definition"] --> B["function name ← function"] B --> C["Arguments in parentheses"] C --> D["Code in curly braces"] D --> E["Return value"] F["Argument Types"] --> G["Required"] F --> H["Default = value"] F --> I["Variadic ..."] J["Anonymous"] --> K["No name needed"] J --> L["Lambda shortcut \x"]
You Did It!
You now know how to:
| Concept | What It Does |
|---|---|
| Function Definition | Create your own magic machine |
| Arguments | Give ingredients to your function |
| Default Arguments | Backup values when none given |
| Named Arguments | Call ingredients by name |
| Return Values | Get results back |
| Anonymous Functions | Quick, nameless helpers |
| Lambda Functions | Super short syntax |
| Variadic Arguments | Accept any number of inputs |
Go build amazing things with your new powers!
