Skip to content
sawnaanwas edited this page Dec 31, 2019 · 12 revisions

What function allows you to tell if an object is a function? What function allows you to tell if a function is a primitive function?

is.function, is.primitive


This code makes a list of all functions in the base package.

objs <- mget(ls("package:base"), inherits = TRUE)
funs <- Filter(is.function, objs)

Use it to answer the following questions:

Which base function has the most arguments?

Alathea:

The arguments can be obtained using the function formals.

require(plyr)
# create a vector of lengths
arg_length <- lapply(funs, function(x)(length(formals(x))))

# find the max
max_args <- which(arg_length == max(unlist((arg_length)))

# get the name of the function
names(funs[max_args])

The function is scan()

How many base functions have no arguments? What’s special about those functions.

Alathea:

Continuing from the code above:

length(which(arg_length == 0))

How could you adapt the code to find all primitive functions?

Alathea:

prims <- Filter(is.primitive, objs)
names(prims)

What are the three important components of a function?

formals(): the arguments body(): the function content environment(): the environment where the variables are stored


When does printing a function not show what environment it was created in?

If the function has a custom print method, or if it is a primitive function.


What does the following code return? Why? What does each of the three c’s mean?

c <- 10
c(c = c)

The first c() runs the combine function to create a vector with an item named c with value 10


What are the four principles that govern how R looks for values?

name masking, functions vs. variables, a fresh start, dynamic lookup


What does the following function return? Make a prediction before running the code yourself.

f <- function(x) {
  f <- function(x) {
    f <- function(x) {
      x ^ 2
    }
    f(x) + 1
  }
  f(x) * 2
}
f(10)

Alathea:

The function will go down to the lowest level and find x ^ 2 so f(x) <- 100. Next, R will arrive at the command f(x) + 1 and get 100 + 1 = 101 and finally multiply by two to get 202


Clarify the following list of odd function calls:

x <- sample(replace = TRUE, 20, x = c(1:10, NA))

x <- sample(c(1:10, NA), 20, replace = TRUE)

y <- runif(min = 0, max = 1, 20)

y <- runif(20, 0, 1)

cor(m = "k", y = y, u = "p", x = x)

cor(x, y, use = "pairwise", method = "kendall")


What does this function return? Why? Which principle does it illustrate?

f1 <- function(x = {y <- 1; 2}, y = 0) {
  x + y
}
f1()

What does this function return? Why? Which principle does it illustrate?

f2 <- function(x = z) {
  z <- 100
  x
}
f2()

Create a list of all the replacement functions found in the base package. Which ones are primitive functions?


What are valid names for user created infix functions?

Anything surrounded in %% e.g. %my_function%


Create an infix xor() operator.

Alathea:

%xor% <- function(x, y) { xor(x, y) }


Create infix versions of the set functions intersect(), union(), and setdiff().

Alathea:

`%=%` <- function(x, y)
{
  intersect(x, y)
}

`%+%` <- function(x, y)
{
  union(x, y)
}

`%-%` <- function(x, y)
{
  setdiff(x, y)
}

Create a replacement function that modifies a random location in a vector.


How does the chdir parameter of source() compare to in_dir()? Why might you prefer one approach to the other?


What function undoes the action of library()? How do you save and restore the values of options() and par()?

Alathea:

detach will remove the library.

options() and par() work the same weird way as setwd(). You can save them while also changing them. So old <- options(newopts) will actually save the old options while also setting the new ones.


Write a function that opens a graphics device, runs the supplied code, and closes the graphics device (always, regardless of whether or not the plotting code worked).

Alathea:

plotter <- function()
{
  x <- seq(1:10)
  y <- runif(10)
  plot(x, y)
  on.exit(dev.off())
}

We can use on.exit() to implement a simple version of capture.output().

capture.output2 <- function(code) {
  temp <- tempfile()
  on.exit(file.remove(temp), add = TRUE)

  sink(temp)
  on.exit(sink(), add = TRUE)

  force(code)
  readLines(temp)
}
capture.output2(cat("a", "b", "c", sep = "\n"))
#> [1] "a" "b" "c"

You might want to compare this function to the real capture.output() and think about the simplifications I’ve made. Is the code easier to understand or harder? Have I removed important functionality?


Compare capture.output() to capture.output2(). How do the functions differ? What features have I removed to make the key ideas easier to see? How have I rewritten the key ideas to be easier to understand?

Clone this wiki locally