Given an arbitrary fixed expression, I want to substitute a single symbol with a collection of multiple values. Examples:
Expression | Symbol | Replace with | Desired Output
-----------------------------------------------------------------------------------------
f(x, 5) | x | a = 1, b = sym, c = "char" | f(a = 1, b = sym, c = "char", 5)
g(f(h(y)), z) | y | 1, 2, 3 | g(f(h(1, 2, 3)), z)
g(f(h(y), z), z) | z | 4, x | g(f(h(y), 4, x), 4, x)
The substitute()
function comes close, but it is not exactly what I am looking for. In the example below, I want to turn f(x)
into f(1, b = 4, c = d)
, but I have not yet found the right env
argument.
substitute(
expr = f(x),
env = list(x = list(1, b = 4, c = rlang::sym("d")))
)
#> f(list(1, b = 4, c = d))
substitute(
expr = f(x),
env = list(x = as.call(c(quote(x), 1, b = 4, c = quote(d)))[-1])
)
#> f(1(b = 4, c = d))
Created on 2019-02-09 by the reprex package (v0.2.1)
Is it possible to find an env
such that substitute(f(x), env)
equals f(1, b = 4, c = d)
?
Remarks:
f(x)
. We cannot simply write as.call(c(quote(f), env))
.!!!
from tidy evaluation because all tidy evaluation in drake
needs to be handled separately.Here's a take on a splicing function
splice <- function(x, replacements) {
if (is(x, "call")) {
as.call(do.call("c",lapply(as.list(x), splice, replacements), quote=T))
} else if (is(x, "name")) {
if (deparse(x) %in% names(replacements)) {
return(replacements[[deparse(x)]])
} else {
list(x)
}
} else {
list(x)
}
}
It seems to work with the sample input
splice(quote(f(x, 5) ), list(x=list(a = 1, b = quote(sym), c = "char" )))
# f(a = 1, b = sym, c = "char", 5)
splice(quote(g(f(h(y)), z)) , list(y=list(1,2,3)))
# g(f(h(1, 2, 3)), z)
splice(quote(g(f(h(y), z), z)), list(z=list(4, quote(x))) )
# g(f(h(y), 4, x), 4, x)
Basically you just swap out the symbol names. it should also work with single variable replacements that aren't in a list.
splice(quote(f(x,5)), list(x=7))
# f(7, 5)
You basically need to re-write the call by manipulating it as a list. This is what the tidyverse functions are doing behind the scene. They intercept the current call, re-write it, then evaluate the newly expanded call. substitute
will never work because you aren't just replacing one symbol with one value. You need to change the number of parameters you are passing to a function.