Skip to content

Instantly share code, notes, and snippets.

@jennybc
Last active October 26, 2017 18:04
Show Gist options
  • Save jennybc/37481d9d784d2e8222b3 to your computer and use it in GitHub Desktop.
Save jennybc/37481d9d784d2e8222b3 to your computer and use it in GitHub Desktop.
What R's lazy evaluation does and does not imply

Lazy evaluation hang nail

Jenny Bryan
18 July, 2014

A group of us at UBC are working through Wickham's Advanced R Programming book together. We just tackled the chapter on Functions, which reminded me of this ...

In the subsection on "Default and missing arguments", we have: "Since arguments in R are evaluated lazily (more on that below), the default value can be defined in terms of other arguments:"

g <- function(a = 1, b = a * 2) {
  c(a, b)
}
g()
## [1] 1 2
g(10)
## [1] 10 20

My previously foggy understanding of lazy evaluation gave me hope that the following would work:

z <- data.frame(x = 1:3, y = x^2)
## Error: object 'x' not found

But clearly it never has, which just confirmed I did not understand lazy evaluation.

Here is a nutty way to make variables derived from other variables at the time of data frame creation:

lazy_this <- function(x = 1:3, y = x^2) {
  data.frame(x, y)
}
lazy_this()
##   x y
## 1 1 1
## 2 2 4
## 3 3 9

So I conclude ... that lazy evaluation applies at the time of function definition, not invocation?

Is there truly no plyr::mutate() (or within()) for de novo data frame creation?

UPDATE

Yes, Hadley confirmed that

@JennyBryan right lazy evaluation only applies at function creation; you could do non-standard evaluation, but data.frame() doesn't

— Hadley Wickham (@hadleywickham) July 18, 2014

which settles the lazy evaluation question. As for the quest to define variables in terms of other variables, Vince Buffalo had a clever suggestion

@JennyBryan @hadleywickham There's always with(): with(list(x=1:3), data.frame(x=x, y=x^2))

— Vince Buffalo (@vsbuffalo) July 18, 2014

More back and forth lead to this, which gives hope maybe one day data_frame() function we deserve will exist ...

@JennyBryan have thought about adding dplyr::data_frame that works how you expect (and wouldn't coerce strings to factors)

— Hadley Wickham (@hadleywickham) July 18, 2014
---
title: "Lazy evaluation hang nail"
author: "Jenny Bryan"
date: "18 July, 2014"
output:
html_document:
keep_md: TRUE
---
```{r setup, include = FALSE, cache = FALSE}
knitr::opts_chunk$set(error = TRUE)
```
A [group of us at UBC](https://github.com/aammd/UBCadv-r) are working through Wickham's [Advanced R Programming](http://adv-r.had.co.nz/) book together. We just tackled the chapter on [Functions](http://adv-r.had.co.nz/Functions.html), which reminded me of this ...
In the subsection on "Default and missing arguments", we have: "Since arguments in R are evaluated lazily (more on that below), the default value can be defined in terms of other arguments:"
```{r}
g <- function(a = 1, b = a * 2) {
c(a, b)
}
g()
g(10)
```
My previously foggy understanding of lazy evaluation gave me hope that the following would work:
```{r}
z <- data.frame(x = 1:3, y = x^2)
```
But clearly it never has, which just confirmed I did not understand lazy evaluation.
Here is a nutty way to make variables derived from other variables at the time of data frame creation:
```{r}
lazy_this <- function(x = 1:3, y = x^2) {
data.frame(x, y)
}
lazy_this()
```
So I conclude ... that lazy evaluation applies at the time of function definition, not invocation?
Is there truly no `plyr::mutate()` (or `within()`) for *de novo* data frame creation?
__UPDATE__
Yes, Hadley confirmed that
<blockquote class="twitter-tweet" lang="en"><p><a href="https://twitter.com/JennyBryan">@JennyBryan</a> right lazy evaluation only applies at function creation; you could do non-standard evaluation, but data.frame() doesn&#39;t</p>&mdash; Hadley Wickham (@hadleywickham) <a href="https://twitter.com/hadleywickham/statuses/490205229678211072">July 18, 2014</a></blockquote>
which settles the lazy evaluation question. As for the quest to define variables in terms of other variables, Vince Buffalo had a clever suggestion
<blockquote class="twitter-tweet" data-conversation="none" lang="en"><p><a href="https://twitter.com/JennyBryan">@JennyBryan</a> <a href="https://twitter.com/hadleywickham">@hadleywickham</a> There&#39;s always with(): with(list(x=1:3), data.frame(x=x, y=x^2))</p>&mdash; Vince Buffalo (@vsbuffalo) <a href="https://twitter.com/vsbuffalo/statuses/490213352992288769">July 18, 2014</a></blockquote>
More back and forth lead to this, which gives hope maybe one day `data_frame()` function we deserve will exist ...
<blockquote class="twitter-tweet" data-conversation="none" lang="en"><p><a href="https://twitter.com/JennyBryan">@JennyBryan</a> have thought about adding dplyr::data_frame that works how you expect (and wouldn&#39;t coerce strings to factors)</p>&mdash; Hadley Wickham (@hadleywickham) <a href="https://twitter.com/hadleywickham/statuses/490205352940421120">July 18, 2014</a></blockquote>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment