gregmacfarlane
gregmacfarlane

Reputation: 2283

Non-standard evaluation of dot parameters

I have a function that I want to wrap another function around, passing the arguments through as the ... arguments parameters. I'm having trouble learning how to structure the underlying function call with lazyeval Here's a decent MWE,

library(dplyr)

pythag <- function(a, b){
  sqrt(a^2 + b^2)
}
pythag_wrapper <- function(data, ...){
  dplyr::mutate_(data,
    root = lazyeval::interp(~pythag(x), x = ...)
  )
}

In this my pythag_wrapper will do some additional data munging. and pythag in my case has many more than two arguments. The function works just fine, and as intended.

test_data <- dplyr::data_frame(a = runif(10), b = runif(10), c = runif(10)) 

test_data %>%
  dplyr::mutate(
    root = pythag(a = b, b = c)
  )
## # A tibble: 10 × 4
##             a          b         c      root
##         <dbl>      <dbl>     <dbl>     <dbl>
## 1  0.19805337 0.05567241 0.9956758 0.9972311
## 2  0.22642799 0.18871552 0.8690659 0.8893195
## 3  0.09352032 0.57328658 0.7475573 0.9420719
## 4  0.40589832 0.71270806 0.8014196 1.0724860
## 5  0.35896302 0.85889027 0.8197176 1.1872782
## 6  0.66409819 0.02206298 0.1304790 0.1323312
## 7  0.45102742 0.76048535 0.5501899 0.9386410
## 8  0.48249177 0.93670363 0.8280114 1.2502066
## 9  0.05545819 0.12281684 0.9219704 0.9301148
## 10 0.47588862 0.40196106 0.0192433 0.4024214

I've tried all sorts of combinations of lazyeval::interp, lazy_eval::lazy_dots, etc., but I can't understand what exactly is supposed to happen, much less how to solve my problem.

pythag_wrapper(test_data, a = "a", b = "b")

## Error: object 'x' not found 

Upvotes: 2

Views: 357

Answers (1)

Lorenzo Rossi
Lorenzo Rossi

Reputation: 1481

The problem in your code is on how you deal with the dots argument ....

Slightly changing your code and 'manually' rewriting the formula inside the wrapper it works fine:

pythag_wrapper <- function(data, ...){
   # From ... argument get names and values
   dots = list(...)

   # 'Write' the formula: ' ~ pythag(a = val1, b = val2)'
   yourformula = as.formula(
      paste0(" ~ pythag(", 
         paste0(names(dots), " = ", unlist(dots), collapse = ", "),
         ")")
       )

   # Apply the mutate_. The setNames here is what you need to 
      # apply the right name to the resulting column
   dplyr::mutate_(data, .dots = setNames(list(yourformula), 'root'))
}

Upvotes: 1

Related Questions