Lesson 10 of 17 · Week 05 · Thu Oct 22

Functions Explained

Questions

Objectives

Why write functions?

If you've copied and pasted a block of code twice, it's time for a function. A function gives a name to a piece of work, so you can reuse it, test it once, and fix it in one place.

mm_to_inches <- function(mm) {
  inches <- mm / 25.4
  return(inches)
}
mm_to_inches(254)          # 10
mm_to_inches(c(10, 100))   # vectorized for free, because / is

Anatomy: a name, the keyword function, the arguments in parentheses, and the body in braces. The function returns the value given to return(), or, if there's no return(), the value of the last line. Variables created inside a function (like inches) exist only while it runs.

Adapted from Software Carpentry's “Functions Explained” episode (CC BY 4.0, The Carpentries). Text, examples and exercises have been rewritten for this course.

Building functions from functions

inches_to_feet <- function(inches) inches / 12
mm_to_feet <- function(mm) {
  inches_to_feet(mm_to_inches(mm))
}

Small functions that do one thing are easy to check. Combining them builds bigger tools you can trust.

Defensive programming

A function should fail loudly and early when it gets input it can't handle, rather than quietly returning nonsense. stopifnot() stops with an error if any condition is FALSE. stop() lets you write your own message:

mm_to_inches <- function(mm) {
  stopifnot(is.numeric(mm))
  if (any(mm < 0)) {
    stop("lengths can't be negative")
  }
  mm / 25.4
}
mm_to_inches("12")    # Error: is.numeric(mm) is not TRUE

Functions on data frames, with defaults

country_rows <- function(dat, ctry, yr = NULL) {
  keep <- dat$country == ctry
  if (!is.null(yr)) {
    keep <- keep & dat$year %in% yr
  }
  dat[keep, ]
}
country_rows(gm, "Kenya")                 # all years: yr uses its default, NULL
country_rows(gm, "Kenya", yr = 2007)

An argument with a default (yr = NULL) can be left out. NULL is a common way to say “not given”, and is.null() checks for it. Arguments can be given by position or by name; names make calls easier to read.

Text in, text out

paste("tidy", "data")                             # "tidy data"   (sep = " " by default)
paste0("tidy", "data")                            # "tidydata"
paste(c("tidy", "data"), collapse = " ")          # squash a vector into one string

Exercises

Each exercise gives you up to 10 checked attempts. Use Run as many times as you like to experiment first, then click Check answer when you're ready. Your exercises use numbers/subsets unique to you, so answers won't match a classmate's exactly.

Exercise 1 — Knots to km/h

0 / 10 attempts used

Write a function knots_to_kmh() that takes a speed in knots and returns it in km/h. One knot is 1.852 km/h.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 2 — Compose two functions

0 / 10 attempts used

kmh_to_ms() (km/h to metres per second) is already defined for you. Write knots_to_kmh() again, then write knots_to_ms() that converts knots to m/s by calling both functions, not by using a new number.

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 3 — Fail loudly

0 / 10 attempts used

Make knots_to_kmh() defensive: it should stop with an error if knots isn't numeric, or if any speed is negative. It should still convert valid speeds correctly. Test it with knots_to_kmh("fast") and knots_to_kmh(-3).

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 4 — Total GDP, then and now

0 / 10 attempts used

Write total_gdp(dat, ctry, yr) that returns a country's total GDP (population × GDP per capita) in one year, from a gapminder-style data frame. Then use it to store in growth how many times larger your country's total GDP was in y2 than in y1 (click Run for your country and years).

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Exercise 5 — Frame some text

0 / 10 attempts used

Write frame_text(text, border) that returns one string: the border, a space, all the words of text joined by spaces, a space, and the border again. For example, frame_text(c("tidy", "data"), "~~") returns "~~ tidy data ~~".

Pasting isn't accepted here — please type your answer so it reflects your own work.

      

Key Points

Proof of completion

Once you've attempted every exercise above, download a PDF summary of your work on this lesson — your name, the exercises you passed, attempt counts, timing, and your final code for each.