Circular definition of function - r

I read a question on function arguments which included the formals function and I was eager to find out how the function is defined. I used base:::formals and it gives:
function (fun = sys.function(sys.parent()))
{
if (is.character(fun))
fun <- get(fun, mode = "function", envir = parent.frame())
.Internal(formals(fun))
}
To me it is unclear how this works because inside the definition of the formals function the formals function is used. That seems paradox to me.

.Internal(formals(fun)) calls an internal R function, coded in C. It just happens that this C internal function is also named formals.
So it does not call the same function, just an internal one that happens to be internally named "formals".
cf https://stat.ethz.ch/R-manual/R-devel/library/base/html/Internal.html

Related

How to handle unknown methods/generics in R

Many languages have special ways to handle unknown methods (examples). The one I'm most familiar with is Python's __getattr__. If someone calls a method you haven't defined for the class, __getattr__ acts as a catch-all and does something.
I've been reading up on S4 and a little on R6, but I haven't found how to do it in R. Is it possible?
No there is no standard way of doing this from inside your class definition as you would do in python.
In python you would do something like MyObject.my_method() while in R with S3 or S4 this would be my_method(MyObject) so it looks exactly like my_function(MyObject). The only difference is that under the hood the function you called dispatches the call to the adequate method. Defining these methods for multiple classes is done as follows:
mean <- function (x, ...) UseMethod("mean", x)
mean.numeric <- function(x, ...) sum(x) / length(x)
mean.data.frame <- function(x, ...) sapply(x, mean, ...)
mean.matrix <- function(x, ...) apply(x, 2, mean)
mean.default <- function(x, ...) {
# do something
}
However, if you call the mean function on a class for which no method has been defined, it is up to the function to handle this, not to the class.
Then you have RC and S6 objects which have a more python-like syntax (MyObject$my_method()), however they would just throw an error that there is no corresponding field or method for the class you used.
Error in envRefInferField(x, what, getClass(class(x)), selfEnv) :
"my_method" is not a valid field or method name for reference class “MyObject”
Here some infos about OO-programing in R.
Winston Chang provided great info here:
https://github.com/r-lib/R6/issues/189#issuecomment-506405998
He explains how you can create an S3 generic function $ for your class to catch unknown methods. Read his full reply for more details, but the key function is below (Counter is the name of the class).
`$.Counter` <- function(x, name) {
if (name %in% names(x)) {
.subset2(x, name)
} else {
function(...) {
.subset2(x, "do")(name, ...)
}
}
}
"If name is in the class, do that. If not, send name (and any arguments) to a function called do() defined in the class."
While I've marked this as the answer (because it solves the problem), jkd is still correct:
No there is no standard way of doing this from inside your class definition as you would do in python.

Converting object of class function into function

In R, assume an object of type 'closure' called my_object that contains both a likelihood function and the associated parameters.
Assume further that I would now like to extract specifically the likelihood function from said object and pass it on to a different R command, which needs a likelihood function as its first argument. I can extract said function via command unenclose in library pryr.
> library(pryr)
> lik_func = unenclose(my_object)
> lik_func
function (pars, condition.surv = TRUE, root = ROOT.OBS, root.p = NULL,
intermediates = FALSE)
{ #function_specifics_here# }
<environment: namespace:diversitree>
However, what I apparently extract is just an object of class 'function', and not the likelihood function itself, as the next R command complains that it does not actually receive a function, but an object:
> asr.marginal(lik=lik_func, pars=my_pars)
Error in UseMethod("make.asr.marginal") :
no applicable method for 'make.asr.marginal' applied to an object of class "function"
How do I convert this object of class 'function' into a plain function, assuming such a distinction actually exists?
Note: I am uncertain if or why a distinction between an object of class 'function' and a plain function actually exists. Maybe someone answering this question could share some light on this too.
“Objects of class "function"” are, generally1, functions. In particular, they are objects of type "closure" and class "function".
Using pryr::unenclose doesn’t have any useful effect here. Its only effect is to take a function and replace all references to objects in an enclosing environment with their value. So if I have, say:
x = 1
f = function () x
… then unenclose(f) will yield:
function () 1
This doesn’t make f any more or less of a function.
Your error message seems to be fundamentally unrelated to that. Instead, asr.marginal specifically expects a likelihood function, which apparently needs to be created by one of the make.* functions in the package. A likelihood function in the context of ‹diversitree› is a function of class "dtlik".
1 The exception is if you are prone to shenanigans:
x = 42
class(x) = "function"
Now x has class function but obviously isn’t a function.

R: wrapper function(fun, parameters) that calls fun with "unrolled" parameters

I would like to implement a generic function:
call_with_parameters <- function(func, parameters) {
call func with parameters and return result
}
that calls the given function func (given as paramter) with a list of parameters, so func must not be able to cope with generic parameters (like ...). As return the call
For example to call: mean(x=1:4, na.rm=TRUE) as
call_with_parameters(mean, list(x=1:4, na.rm=TRUE))
Any suggestions?
I think, you are looking for do.call for the construction of function calls.
The function constructs the call and evaluates it immediately( You can also use call to construct the call and evaluates it later using eval for example). do.call takes the arguments
from an object of mode "list" containing all the arguments of function to be evaluated. For example:
do.call("mean", list(x=1:4,na.rm=TRUE))
is equivalent to :
mean(x=1:4,na.rm=TRUE)

When/how/where is parent.frame in a default argument interpreted?

Truth be told, I'm just being lazy here, but perhaps someone could someday profit from the answer being here.
Say I define a function like:
fn<-function(envir=parent.frame())
{
#do something with envir
}
My question is: what might I expect to be the content of envir?
Context: I had a rather long function f1 that contained a call to parent.frame. Now, I want to extract part of that function (containing the parent.frame call) into a new helper function f2 (which will then be called by f1), and I want to be sure that f1 does the same as it did before.
Default arguments are evaluated within the evaluation frame of the function call, from which place parent.frame() is the calling environment. envir's value will thus be a pointer to the environment from which fn was called.
Also, just try it out to see for yourself:
debug(fn)
fn()
# debugging in: fn()
# debug at #2: {
# }
Browse[2]> envir
# <environment: R_GlobalEnv>

Environment chaining in R

In my R development I need to wrap function primitives in proto objects so that a number of arguments can be automatically passed to the functions when the $perform() method of the object is invoked. The function invocation internally happens via do.call(). All is well, except when the function attempts to access variables from the closure within which it is defined. In that case, the function cannot resolve the names.
Here is the smallest example I have found that reproduces the behavior:
library(proto)
make_command <- function(operation) {
proto(
func = operation,
perform = function(., ...) {
func <- with(., func) # unbinds proto method
do.call(func, list(), envir=environment(operation))
}
)
}
test_case <- function() {
result <- 100
make_command(function() result)$perform()
}
# Will generate error:
# Error in function () : object 'result' not found
test_case()
I have a reproducible testthat test that also outputs a lot of diagnostic output. The diagnostic output has me stumped. By looking up the parent environment chain, my diagnostic code, which lives inside the function, finds and prints the very same variable the function fails to find. See this gist..
How can the environment for do.call be set up correctly?
This was the final answer after an offline discussion with the poster:
make_command <- function(operation) {
proto(perform = function(.) operation())
}
I think the issue here is clearer and easier to explore if you:
Replace the anonymous function within make_command() with a named one.
Make that function open a browser() (instead of trying to get result). That way you can look around to see where you are and what's going on.
Try this, which should clarify the cause of your problem:
test_case <- function() {
result <- 100
myFun <- function() browser()
make_command(myFun)$perform()
}
test_case()
## Then from within the browser:
#
parent.env(environment())
# <environment: 0x0d8de854>
# attr(,"class")
# [1] "proto" "environment"
get("result", parent.env(environment()))
# Error in get("result", parent.env(environment())) :
# object 'result' not found
#
parent.frame()
# <environment: 0x0d8ddfc0>
get("result", parent.frame()) ## (This works, so points towards a solution.)
# [1] 100
Here's the problem. Although you think you're evaluating myFun(), whose environment is the evaluation frame of test_case(), your call to do.call(func, ...) is really evaluating func(), whose environment is the proto environment within which it was defined. After looking for and not finding result in its own frame, the call to func() follows the rules of lexical scoping, and next looks in the proto environment. Neither it nor its parent environment contains an object named result, resulting in the error message you received.
If this doesn't immediately make sense, you can keep poking around within the browser. Here are a few further calls you might find helpful:
environment(get("myFun", parent.frame()))
ls(environment(get("myFun", parent.frame())))
environment(get("func", parent.env(environment())))
ls(environment(get("func", parent.env(environment()))))

Resources