← R EnglishChapter 05 of 13

Functions

## Learning Objectives - Create and call functions - Understand parameters and arguments - Master function scoping - Work with anonymous functions - Handle variable arguments ## Defining Functions ### Basic Function ```r # Function definition greet <- function() { print("Hello, World!") } # Call function greet() ``` ### Function with Parameters ```r # Single parameter greet <- function(name) { paste("Hello,", name) } greet("Alice") # "Hello, Alice" # Multiple parameters add <- function(a, b) { a + b } add(3, 5) # 8 ``` ### Default Parameters ```r # Default values greet <- function(name = "World") { paste("Hello,", name) } greet() # "Hello, World" greet("Alice") # "Hello, Alice" # Multiple defaults power <- function(base, exp = 2) { base ^ exp } power(3) # 9 power(3, 3) # 27 ``` ## Return Values ### Explicit Return ```r # Using return() absolute <- function(x) { if (x < 0) { return(-x) } return(x) } absolute(-5) # 5 absolute(5) # 5 ``` ### Implicit Return ```r # Last expression returned automatically absolute <- function(x) { if (x < 0) -x else x } # Common mistake get_info <- function(x) { if (x > 0) { print("positive") # NULL returned! } "done" } ``` ### Returning Multiple Values ```r # Return as list stats <- function(x) { list( mean = mean(x), median = median(x), sd = sd(x) ) } result <- stats(1:10) result$mean # 5.5 result$median # 5.5 ``` ## Named Arguments ### Using Names ```r # Call with names power(base = 3, exp = 2) # Order doesn't matter with names power(exp = 2, base = 3) # Mix positional and named power(3, exp = 2) ``` ### Partial Matching ```r power <- function(base = 2, exponent = 1) { base ^ exponent } power(e = 3) # Works: e matches exponent ``` ## Scoping ### Environment Basics ```r # Variables outside function are visible global_var <- 10 my_func <- function() { print(global_var) # 10 } my_func() ``` ### Local Variables ```r my_func <- function() { local_var <- 20 # Only exists inside function print(local_var) } my_func() # global_var # Error: object not found ``` ### Assignment Creates Local ```r x <- 10 my_func <- function() { x <- 20 # Creates new local variable print(x) # 20 } my_func() print(x) # 10 (unchanged) ``` ### Using <<- for Global Assignment ```r x <- 10 my_func <- function() { x <<- 20 # Modifies global variable print(x) } my_func() # 20 print(x) # 20 ``` ## Anonymous Functions ### No Name Functions ```r # Anonymous function function(x) x ^ 2 # Assign to variable square <- function(x) x ^ 2 # Or use anonymous directly (function(x) x ^ 2)(5) # 25 ``` ### In Apply Functions ```r nums <- list(a = 1:3, b = 4:6) # Anonymous in lapply lapply(nums, function(x) sum(x) / length(x)) # Anonymous in sapply sapply(1:3, function(x) if (x %% 2 == 0) "even" else "odd") ``` ## Variable Arguments ### ... (Ellipsis) ```r # Pass through arguments print_all <- function(...) { args <- list(...) for (arg in args) { print(arg) } } print_all(1, "hello", TRUE, c(1, 2, 3)) ``` ### Partial Application ```r # Fix some arguments power <- function(base, exp) { base ^ exp } square <- function(x) power(x, 2) cube <- function(x) power(x, 3) square(5) # 25 cube(5) # 125 ``` ## Function as Return Value ### Returning Functions ```r # Function factory make_power <- function(exp) { function(x) { x ^ exp } } square <- make_power(2) cube <- make_power(3) square(5) # 25 cube(5) # 125 ``` ## Function Operators ### Pipe with Functions ```r # R 4.1+ native pipe 1:10 |> sum() |> sqrt() # Older style library(magrittr) 1:10 %>% sum() %>% sqrt() ``` ## Closure ### Capturing Environment ```r # Counter example using closure make_counter <- function() { count <- 0 function() { count <<- count + 1 count } } counter1 <- make_counter() counter2 <- make_counter() counter1() # 1 counter1() # 2 counter1() # 3 counter2() # 1 (separate count) ``` ## Vectorized Functions ### Making Functions Vectorized ```r # Your function only takes single value add_one <- function(x) x + 1 # Vectorize it add_one_vectorized <- Vectorize(add_one) add_one_vectorized(1:5) # 2 3 4 5 6 ``` ## Error Handling ### tryCatch ```r # Basic error handling safe_divide <- function(a, b) { tryCatch({ if (b == 0) stop("Division by zero") a / b }, error = function(e) { message("Error: ", e$message) NA }) } safe_divide(10, 2) # 5 safe_divide(10, 0) # NA with message ``` ### try for Debugging ```r # try continues even on error result <- try({ # Risky code x <- 1:3 y <- c("a", "b") x + y # Error! }) if (inherits(result, "try-error")) { print("Operation failed") } ``` ## Summary - Functions defined with `function()` and assigned to variables - Parameters can have default values - Use `return()` for explicit returns (or last expression) - Use `list()` to return multiple values - Scoping: local variables shadow global - Use `<<-` to modify global variables - Anonymous functions useful in apply family - Use `...` for variable arguments - `Vectorize()` makes functions work on vectors - `tryCatch()` for error handling

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →