Advanced: Why ?function(){} works in R - r

I understand some operators and functions in R need to be backquoted before using the help function. However, I don't understand why ?function(){} also works. Does anyone have any idea on it?

Let's see what happens in ?'s code using the {flow} package, it helps you inspect the logical path your code takes (follow the full lines):
flow::flow_run(?function(){}, out = "png")
We see that when the expression is a call we call utils:::.helpForCall
Let's see what happens there, we cannot call flow::flow_run directly so we call flow::flow_debugonce to set up utils:::.helpForCall and call ? again
flow::flow_debugonce(utils:::.helpForCall, out = "png")
?function(){}
There we see that when the input is a call we call utils:::.tryHelp on the name of the function as a string. function(){} is a call to function
and utils:::.tryHelp("function") opens the help file.
Bonus
#rawr wonders why ?cars[1] doesn't work, I haven't looked much into it but at a glance we see where the code takes a different path in .helpForCall:
flow::flow_debugonce(utils:::.helpForCall, out = "png")
?mtcars[1]

If you try
debugonce(`?`)
?function(){}
you will arrive at this line
if (is.call(topicExpr))
return(.helpForCall(topicExpr, parent.frame()))
So calling
debugonce(.helpForCall)
again will get to this line in .helpForCall
f <- expr[[1L]]
If you examine expr, it is a ?call with the following elements
expr
# function() {
# }
as.list(expr)
# [[1]]
# `function`
#
# [[2]]
# NULL
#
# [[3]]
# {
# }
#
# [[4]]
# function(){}
and
class(expr[[1]])
# [1] "name"
Now, if you would ask me why
?mtcars[1]
# Error in .helpForCall(topicExpr, parent.frame()) :
?mtcars[[1]] ## works
?asdflasdflansldfnalsdf[1]
# Error in eval(argExpr, envir) : object 'asdflasdflansldfnalsdf' not found
?asdflasdflansldfnalsdf[[1]] ## works
I have no idea

Related

How to program over match.call?

I'm trying to program over a function inside a package, but I'm stuck with the function internally using match.call() to parse one of its arguments.
A super-simplified example of the function with the usual utilization could look like this:
f1 = function(x, y=0, z=0, a=0, b=0){ #lots of arguments not needed for the example
mc = match.call()
return(mc$x)
#Returning for testing purpose.
#Normally, the function later uses calls as character:
r1 = as.character(mc$x[1])
r2 = as.character(mc$x[2])
#...
}
x1 = f1(x = foo(bar))
x1
# foo(bar)
class(x1)
# [1] "call"
In my case, I need to get the value of x from a variable (value in the following code). Expected utilisation of f1 is as following :
value = "foo(bar)" #this line could also be anything else
f1(x=some_magic_function(value))
# Expected result = foo(bar)
# Unwanted result = some_magic_function(value)
Unfortunately, match.call() always return the very input value. I'm quite out of my league here so I only tried few functions.
Is there any way I could trick match.call() so it could accept external variable ?
Failed attempts so far:
#I tried to create the exact same call using rlang::sym()
#This may not be the best way...
value = call("foo", rlang::sym("bar"))
value
# foo(bar)
class(value)
# [1] "call"
x1==value
# [1] TRUE
f1(x=value)
# value
f1(x=eval(value))
# eval(value)
f1(x=substitute(value))
# substitute(value)
There's nothing you can include as a parameter to f1 to make this work. Instead, you would dynamically need to build your call to f1. With base R you might do this with do.call.
do.call("f1", list(parse(text=value)[[1]]))
or with rlang
eval_tidy(quo(f1(!!parse_expr(value))))

Why must local({...}) be defined using two rounds of expression quoting?

I'm trying to understand how R's local function is working. With it, you can open a temporary local scope, which means what happens in local (most notably, variable definitions), stays in local. Only the last value of the block is returned to the outside world. So:
x <- local({
a <- 2
a * 2
})
x
## [1] 4
a
## Error: object 'a' not found
local is defined like this:
local <- function(expr, envir = new.env()){
eval.parent(substitute(eval(quote(expr), envir)))
}
As I understand it, two rounds of expression quoting and subsequent evaluation happen:
eval(quote([whatever expr input]), [whatever envir input]) is generated as an unevaluated call by substitute.
The call is evaluated in local's caller frame (which is in our case, the Global Environment), so
[whatever expr input] is evaluated in [whatever envir input]
However, I do not understand why step 2 is nessecary. Why can't I simply define local like this:
local2 <- function(expr, envir = new.env()){
eval(quote(expr), envir)
}
I would think it evaluates the expression expr in an empty environment? So any variable defined in expr should exist in envir and therefore vanish after the end of local2?
However, if I try this, I get:
x <- local2({
a <- 2
a * 2
})
x
## [1] 4
a
## [1] 2
So a leaks to the Global Environment. Why is this?
EDIT: Even more mysterious: Why does it not happen for:
eval(quote({a <- 2; a*2}), new.env())
## [1] 4
a
## Error: object 'a' not found
Parameters to R functions are passed as promises. They are not evaluated unless the value is specifically requested. So look at
# clean up first
if exists("a") rm(a)
f <- function(x) print(1)
f(a<-1)
# [1] 1
a
# Error: object 'a' not found
g <- function(x) print(x)
g(a<-1)
# [1] 1
a
# [1] 1
Note that in the g() function, we are using the value passed to the function which is that assignment to a so that creates a in the global environment. With f(), that variable is never created because that function parameter remained a promise end was never evaluated.
If you want to access a parameter without evaluating it, you need to use something like match.call() or subsititute(). The local() function does the latter.
If you remove the eval.parent(), you'll see that the substitute puts the un-evaluated expression from the parameter into a new call to eval().
h <- function(expr, envir = new.env()){
substitute(eval(quote(expr), envir))
}
h(a<-1)
# eval(quote(a <- 1), new.env())
Where as if you do
j<- function(x) {
quote(x)
}
j(a<-1)
# x
you are not really creating a new function call. Further more when you eval() that expression, you are triggering the evaluation of x from it's original calling environment (triggering the evaluation of the promise), not evaluating the expression in a new environment.
local() then uses the eval.parent() so that you can use existing variables in the environment within your block. For example
b<-5
local({
a <- b
a * 2
})
# [1] 10
Look at the behaviors here
local2 <- function(expr, envir = new.env()){
eval(quote(expr), envir)
}
local2({a<-5; a})
# [1] 5
local2({a<-5; a}, list(a=100, expr="hello"))
# [1] "hello"
See how when we use a non-empty environment, the eval() is looking up expr in the environment, it's not evaluating your code block in the environment.

Unexpected behavior with on.exit(..., add = TRUE)

First, please note that the following code creates and removes a folder in the current directory. If it conflicts with any of your file names, don't run this code. I'm not sure how to explain this question without it.
In fun1 I use on.exit(..., add = TRUE) on one line, and on the next I try to remove the directory I created with another on.exit call. It doesn't work.
fun1 <- function(){
if(!file.exists("Rsaber")) dir.create("Rsaber")
on.exit(file.remove(paste0("Rsaber/", list.files("Rsaber"))), add = TRUE)
on.exit(file.remove("Rsaber"))
write.csv("1,2,3,4", file = "Rsaber/new.csv")
}
> fun1()
# Warning message:
# In file.remove("Rsaber") :
# cannot remove file 'Rsaber', reason 'Directory not empty'
> file.exists("Rsaber")
# [1] TRUE
> list.files("Rsaber")
# [1] "new.csv"
However, this method works.
fun2 <- function(){
if(!file.exists("Rsaber")) dir.create("Rsaber")
on.exit(file.remove(c(paste0("Rsaber/", list.files("Rsaber"))), "Rsaber"))
write.csv("1,2,3,4", file = "Rsaber/new.csv")
}
> fun2()
> file.exists("Rsaber")
# [1] FALSE
This second method is also much cleaner and probably the way to go, but
Why doesn't on.exit(..., add = TRUE) behave as expected in fun1 ?
Note that I'm not using a temporary directory here because this is part of a larger function that has a logical argument for determining whether or not to keep a downloaded data file.
System info:
> version[[1]]
# [1] "x86_64-pc-linux-gnu"
I think you need add=TRUE on the second file.remove otherwise the second statement replaces the first:
fun1 <- function(){
if(!file.exists("Rsaber")) dir.create("Rsaber")
on.exit(file.remove(paste0("Rsaber/", list.files("Rsaber"))))
on.exit(file.remove("Rsaber"), add = TRUE)
write.csv("1,2,3,4", file = "Rsaber/new.csv")
}
Also as noted this wont work on windows as the directory will not be considered as a file.
For cross-platform support maybe consider unlink
fun1 <- function(){
if(!file.exists("Rsaber")) dir.create("Rsaber")
on.exit(unlink("Rsaber", recursive = TRUE))
write.csv("1,2,3,4", file = "Rsaber/new.csv")
print(system('ls'))
}

how to remove a variable from inside a function in R

i am trying to create a function in which i want to remove one of the variables passed to it.
now R works in annoying ways in that it copies the object instead of giving a reference.
(technically the copying only happens if you make a change... but meh...)
a=function(b){
rm(b)
# rm(b)
}
test=123
a(test) # will remove b, not test
# you can verify that by adding the 2nd rm(b)
i tried
a=function(b){
rm(match.call()[[2]])
}
but that gives the error:
Error in rm(match.call()[[3]]) :
... must contain names or character strings
Try this:
Foo <- function(x){
Sx <- deparse(substitute(x))
rm(list=Sx,envir=sys.frame(-1))
}
##
Z <- 123
ls()
##
[1] "Foo" "Z"
##
Foo(x=Z)
ls()
[1] "Foo"
similar to nrussell's answer, here's the line from cgwtools::askrm which does an arbitrary function call on the selected object:
call(fn, as.name(thenam)), envir = parent.frame(1))
(and, yes, I'm plugging my own toolkit here :-) )

force-evaluate an object being passed as an argument to a function

I would like to pass the value of an object as an argument to a function.
# This is my object
anObject <- "an_unkown_string"
# I would like to do the equivalent of:
someFunc("an_unkown_string")
# .. by somehow calling on the object containing the string
someFunc( ??? (anObject) )
For example, with the sample function below (based on save()):
someFunc <- function(...) {
names <- as.character(substitute(list(...)))[-1L]
return(names)
}
# Ideally, the output would be:
someFunc( ??? (anObject) )
[1] "an_unkown_string"
I do not have access to modify someFunc
I have tried the following, but with no success.
someFunc(Name_of_Object)
someFunc(eval(Name_of_Object))
someFunc(evalq(Name_of_Object))
someFunc(force(Name_of_Object))
someFunc(eval(parse(text=Name_of_Object)))
Any help is appreciated.
How about
> do.call(someFunc, list(anObject))
[1] "an_unkown_string"
Or you could make a wrapper
myWrap <- function(...) {
do.call(someFunc, as.list(...))
}
> myWrap(anObject)
[1] "an_unkown_string"
Another way to construct a call and evaluate it:
> call("someFunc", anObject)
someFunc("an_unkown_string")
> eval(call("someFunc", anObject))
[1] "an_unkown_string"
I suppose I should mention that ?do.call says
The behavior of some functions, such as substitute, will not be the same for functions evaluated using do.call as if they were evaluated from the interpreter. The precise semantics are currently undefined and subject to change.
Nevertheless, for now at least, anObject is evaluated when the call is constructed (in the call to call or do.call), so substitute finds "an_unknown_string" instead of "anObject".
I'm puzzled. Why are you trying to make this more complex than it realy is?
someFunc <- function(obj) {
return(obj)
}
> someFunc(anObject)
[1] "an_unkown_string"

Resources