Disons que j'ai un objet de type "symbole" représentant le nom d'une fonction. Par example:
nm <- quote(mean)
Je veux construire une fonction f
dont le corps utilise la fonction nommée par le symbole nm
. Par example:
f <- function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = mean(x), nothing = x)
}
Je veux construire cette fonction identique, ce qui implique que je voudrais non Soyez satisfait de l'approche suivante:
factory <- function(name) {
func <- match.fun(name)
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = func(x), nothing = x)
}
}
g <- factory(nm)
puisque le corps de g
n'est pas body(f)
et l'environnement de g
n'est pas environment(f)
.
Une approche que j'ai envisagée est bquote
:
h <- eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
}))
bquote
me fait la majeure partie du chemin, mais un problème est que la sortie print
de h
ne contient pas la valeur substituée de nm
par défaut :
h
## function(x, do = c("something", "nothing")) {
## switch(match.arg(do), something = .(nm)(x), nothing = x)
## }
print(h, useSource = FALSE)
## function (x, do = c("something", "nothing"))
## {
## switch(match.arg(do), something = mean(x), nothing = x)
## }
La cause semble être l'attribut srcref
h
:
identical(f, h)
## [1] TRUE
identical(f, h, ignore.srcref = FALSE)
## [1] FALSE
ma question est : Comment peut-on approcher le problème général de la construction f
de nm
?
Mes conditions sur la fonction construite h
sont que identical(f, h)
doit être TRUE
et que la sortie de print(h)
doit contenir la valeur substituée de nm
, semblable à print(f)
.
J'accueillerais les réponses à améliorer mon approche bquote
ou réponses suggérant une nouvelle approche, ou des réponses expliquant pourquoi ce que je veux faire n'est pas réellement possible ...
Pas particulièrement élégant, mais un parse(deparse(
semble fonctionner:
nm <- quote(mean)
f <- function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = mean(x), nothing = x)
}
eval(parse(text=deparse(bquote(h <- function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}))))
identical(f, h)
#> [1] TRUE
print(f)
#> function(x, do = c("something", "nothing")) {
#> switch(match.arg(do), something = mean(x), nothing = x)
#> }
print(h)
#> function(x, do = c("something", "nothing")) {
#> switch(match.arg(do), something = mean(x), nothing = x)
#> }
srcref
n'est pas identique, comme prévu:
identical(f, h, ignore.srcref = FALSE)
#> [1] FALSE
attributes(attributes(f)$srcref)$srcfile$lines
#> [1] "f <- function(x, do = c(\"something\", \"nothing\")) {"
#> [2] " switch(match.arg(do), something = mean(x), nothing = x)"
#> [3] "}"
attributes(attributes(h)$srcref)$srcfile$lines
#> [1] "h <- function(x, do = c(\"something\", \"nothing\")) {"
#> [2] " switch(match.arg(do), something = mean(x), nothing = x)"
#> [3] "}"
Lecture à travers ?srcref
, Il semble qu'il existe deux manières idiomatiques d'améliorer l'approche bquote
. La première utilisation removeSource
Pour nettoyer récursivement une fonction qui conserve son code source:
h <- removeSource(eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
})))
h
function (x, do = c("something", "nothing"))
{
switch(match.arg(do), something = mean(x), nothing = x)
}
La seconde évite de préserver le code source tout à fait:
op <- options(keep.source = FALSE)
h <- eval(bquote({
function(x, do = c("something", "nothing")) {
switch(match.arg(do), something = .(nm)(x), nothing = x)
}
}))
options(op)
h
function (x, do = c("something", "nothing"))
{
switch(match.arg(do), something = mean(x), nothing = x)
}
En fait, ?options
Dit que la valeur par défaut de keep.source
Est interactive()
, les deux approches sont donc quelque peu redondantes dans des contextes non interactifs.