why ellipsis ... have to be wrapped inside c() when used in lambda functions in purrr
Asked Answered
N

1

2

May be this question termed as part-3 of this question.

I know that arguments in lambda functions when used in tidyverse especially purrr functions are written as -

  • . when there is only 1 argument
  • .x & .y when there are 2
  • OR ..1, ..2 so on when there are > 2 arguments

In the linked question, I learnt that if all the arguments have to be simultaneously passed we may use ellipsis i.e. ....

But my question, why such ... work only when wrapped inside a c() and doesn't work when used as such. In the below two syntaxes, second one works while first one doesn't?

#1 this doesn't work

pmap_df(iris[1:4], ~...)

Error in .f(Sepal.Length = .l[[1L]][[i]], Sepal.Width = .l[[2L]][[i]],  : 
  '...' used in an incorrect context



#2 this however, works and returns the first argument after converting it to a tibble
pmap_df(iris[1:4], ~ c(...))

#see
identical(pmap_df(iris[1:4], ~c(...)), iris[1:4] %>% as_tibble())
[1] TRUE

Can someone explain?

Nitrogenous answered 15/4, 2021 at 10:18 Comment(0)
P
1

The offical documentation has this to be said about the ellipsis:

The components of ‘...’ can be accessed in the usual pairlist manner from C code, but is not easily accessed as an object in interpreted code.

So that's possibly part of the answer to your question: The ellipsis is a not easily accessed object.

You would likely have to go on a safari trip down into the C-code of things to learn more about that.

Now being a not easily accessed object the ... certainly doesn't qualify as a list or vector, which is what pmap_df wants. Although technically it probably could.

However seeing how ~ is used to create one-liner function bodies, the real reason is probably that it itself does not consider the ellipsis in the first place.

Consider:


f <- function( ... ) {
    ~...
}

f(a=1,b=2) ## returns just `~...` , no trace of a and b in the formula's environment either.

Now consider: ~........ . Works just as fine.

~ happily takes any number of dots or other alfa num characters, ~....... or ~aaa......bb...cc... for example, effectively demonstrating it doesn't care about the otherwise normal way to look at the ellipsis and just treats them as part of a name.

Polarize answered 15/4, 2021 at 10:26 Comment(9)
your lambda functions aren't functions. they are formulas. purr is borrowing the ~ operator to create easy to use one-of expression onelinersPolarize
I do however now see that ~... on its own seems to be perfectly fine, I do not have an answer for that right nowPolarize
see as_mapper(~ mean(.x)) gives this output <lambda> function (..., .x = ..1, .y = ..2, . = ..1) mean(.x) attr(,"class") [1] "rlang_lambda_function" "function" Nitrogenous
sure, but that is as_mapper creating a function from the ~-expression, see github.com/tidyverse/purrr/blob/…Polarize
Though I agree that starting with twiddle ~ is only a shortcut style of writing invisible functions inside many of the purrr functions, but my question doesn't pertain to this discussion whether it is a function or formula. My simple question is that why it works only when wrapped around c().Nitrogenous
Well, to circle back, r documentation says ... is not easily accessed as an object. wrapping it in c() or list() circumvents that as one (or two, depending on how you see it) viable technique. To dwelve further on that you would likely have to dig down in C-landPolarize
Sure, its in my answer already. Now being a not easily accessed object, I'm pretty sure ...is not a list. (as then it would be easily accessed)Polarize
Agreed, I gave it a shot, but I am not sure if I fully I captured what you feel is the essense of it so far.Polarize
I arrived at concluding that ~ itself is the problem, irrespective of how easy or hard ... is to access as an object. Tilde plainly doesn't care about the ellipsis. You need c() or list() which do. .. and all of this are things I learned while trying haphazardly to answer your question. But isn't that how one learns anyway.Polarize

© 2022 - 2024 — McMap. All rights reserved.