thothal thothal - 1 month ago 9
R Question

Why can't we use . as a parameter in an anonymous function with %>%

Can somebody explain to me why the two following instructions have different outputs:

library(plyr)
library(dplyr)
ll <- list(a = mtcars, b = mtcars)
# using '.' as a function parameter
llply(ll, function(.) . %>% group_by(cyl) %>% summarise(min = min(mpg)))
# using 'd' as function parameter
llply(ll, function(d) d %>% group_by(cyl) %>% summarise(min = min(mpg)))


The former case is apparently not even evaluated (which I figured by misspelling
summarise
:
llply(ll, function(.) . %>% group_by(cyl) %>% sumamrise(min = min(mpg)))
would not throw an error).

So this has all to do with scoping rules and where things are evaluated, but I really want to understand what is going on, and why this happens? I use
.
as an argument in anonymous functions quite often and I was puzzled to see the outcome.

So long story short, why does
.
not work with
%>%
?

Answer

This seems to be because of the special use of . as a placeholder when using piping. From ?"%>%":

Using the dot for secondary purposes

Often, some attribute or property of lhs is desired in the rhs call in addition to the value of lhs itself, e.g. the number of rows or columns. It is perfectly valid to use the dot placeholder several times in the rhs call, but by design the behavior is slightly different when using it inside nested function calls. In particular, if the placeholder is only used in a nested function call, lhs will also be placed as the first argument! The reason for this is that in most use-cases this produces the most readable code. For example, iris %>% subset(1:nrow(.) %% 2 == 0) is equivalent to iris %>% subset(., 1:nrow(.) %% 2 == 0) but slightly more compact. It is possible to overrule this behavior by enclosing the rhs in braces. For example, 1:10 %>% {c(min(.), max(.))} is equivalent to c(min(1:10), max(1:10)).

Comments