Skip to content
Functional Programming Tools
step 1/5

Reading — step 1 of 5

Learn

~1 min readS4 Classes and Functional Programming

R has rich functional programming primitives. The purrr package (tidyverse) extends them, but base R has plenty:

Map — multi-arg apply:

Map(`+`, 1:3, 10:12)        # list(11, 13, 15)
Map(function(a, b) a * b, 1:3, c(10, 20, 30))   # list(10, 40, 90)

Filter — keep where predicate is TRUE:

Filter(function(x) x > 2, c(1, 2, 3, 4, 5))   # c(3, 4, 5)

Find — first match:

Find(function(x) x > 3, c(1, 2, 5, 4))    # 5

Reduce — fold:

Reduce(`+`, 1:10)                          # 55
Reduce(`+`, 1:10, accumulate = TRUE)       # running sum
Reduce(function(acc, x) c(acc, x * 2), 1:5, init = c())
# c(2, 4, 6, 8, 10)

Function composition — write your own:

compose <- function(f, g) function(x) f(g(x))
incThenDouble <- compose(function(x) x * 2, function(x) x + 1)
incThenDouble(5)                           # 12 = (5+1)*2

Partial application:

partial <- function(f, ...) {
    args <- list(...)
    function(...) do.call(f, c(args, list(...)))
}

add5 <- partial(`+`, 5)
add5(10)                                    # 15

Currying the manual way:

curry <- function(f) {
    function(x) function(y) f(x, y)
}

adder <- curry(`+`)
add5 <- adder(5)
add5(10)                                    # 15

Negate — invert a predicate:

is_negative <- Negate(function(x) x >= 0)
is_negative(-5)                             # TRUE
is_negative(5)                              # FALSE

do.call(f, args) — call f with args from a list:

do.call(`+`, list(3, 4))                    # 7
do.call(paste, list("a", "b", sep = "-"))   # "a-b"

Why this matters: R's strength is data manipulation. Functional tools let you express transformations as pipelines of small functions.

With purrr (tidyverse): map, map2, pmap, keep, discard, compose, partial — same ideas, more consistent API.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…