Is there any way, given a function passed as a parameter, to alter its input parameter string before evaluating it?
Here's pseudo-code for what I'm hoping to achieve:
test.func <- function(a, b) {
# here I want to alter the b expression before evaluating it:
b(..., val1=a)
}
Given the function call passed to b, I want to add in a as another parameter without needing to always specify ... in the b call. So the output from this test.func call should be:
test.func(a="a", b=paste(1, 2))
"1" "2" "a"
Edit:
Another way I could see doing something like this would be if I could assign the additional parameter within the scope of the parent function (again, as pseudo-code); in this case a would be within the scope of t1 and hence t2, but not globally assigned:
t2 <- function(...) {
paste(a=a, ...)
}
t1 <- function(a, b) {
local( { a <<- a; b } )
}
t1(a="a", b=t2(1, 2))
This is somewhat akin to currying in that I'm nesting the parameter within the function itself.
Edit 2:
Just to add one more comment to this: I realize that one related approach could be to use "prototype-based programming" such that things would be inherited (which could be achieved with the proto package). But I was hoping for a easier way to simply alter the input parameters before evaluating in R.
Have you check substitute? I don't know it satisfies you needs but you could use fact that it returns hidden list structure which you can modify as below
test.func <- function(a, b) {
f <- substitute(b)
f[["val1"]] <- a
eval(f)
}
test.func(a="a", b=paste(1, 2))
# "1 2 a"
What do you want to do to the B expression? Do you want to dynamically add behavior? Then there is a decorator pattern in your problem. Want to optionally add behavior? Proxy. Need to swap out one behavior for another under certain circumstances? Strategy.
You are far better off relying on design patterns - which work and make you more effective regardless of the language you use - than you are trying to use some language-specific feature that let's you mutate the behavior of a strategy.
Related
I have one question about using global variable in R. I write two examples
First version:
a <- 1
fun <- function(b){
return(a+b)
}
fun(b)
Second version:
a <- 1
fun <- function(a,b){
return(a+b)
}
fun(a,b)
I want to know which version is correct or recommand.
Relying on global state inside functions is frowned upon for various reasons (which can be roughly grouped under the caption encapsulation. So the second version would be superior in most scenarios.
However, the situation changes once the variable is defined inside a non-global environment. In that case, you’ve encapsulated your state into something that’s put away neatly. This is sometimes useful, because it allows you to create functions based on some input.
The classical example is something like this:
adder = function (value_to_add) {
function (x) {
x + value_to_add
}
}
This may look obscure but it’s simply a function that returns another function: you can use it to create functions. Here, for example, we create a function that takes one argument and adds the value 5 to it:
add5 = adder(5)
And here’s one that adds π to its argument:
add_pi = adder(pi)
Both of these are normal functions:
> add5(10)
[1] 15
> add_pi(10)
[1] 13.14159
Both of these functions, add5 and add_pi, access a variable, value_to_add, that’s outside of the function itself, in a separate environment. And it’s important to realise that these are different environments from each other: add5’s value_to_add is a different value, in a different environment, from add_pi’s value_to_add:
> environment(add5)$value_to_add
[1] 5
> environment(add_pi)$value_to_add
[1] 3.141593
(environment(f) allows you to inspect the environment to which a function f belongs. $ is used to access names inside that environment.)
I am trying to write a very basic IF statement in R and am stuck. I thought I'd find someone with the same problem, but I cant. Im sorry if this has been solved before.
I want to check if a variable/object has been assigned, IF TRUE I want to execute a function that is part of a R-package. First I wrote
FileAssignment <- function(x){
if(exists("x")==TRUE){
print("yes!")
x <- parse.vdjtools(x)
} else { print("Nope!")}
}
I assign a filename as x
FILENAME <- "FILENAME.txt"
I run the function
FileAssignment(FILENAME)
I use print("yes!") and print("Nope!") to check if the IF-Statement works, and it does. However, the parse.vdjtools(x) part is not assigned. Now I tested the same IF-statement outside of the function:
if(exists("FILENAME1")==TRUE){
FILENAME1 <- parse.vdjtools(FILENAME1)
}
This works. I read here that it might be because the function uses {} and the if-statement does too. So I should remove the brackets from the if-statement.
FileAssignment <- function(x){
if(exists("x")==TRUE)
x <- parse.vdjtools(x)
else { print("Nope!")
}
Did not work either.
I thought it might be related to the specific parse.vdjtools(x) function, so I just tried assigning a normal value to x with x <- 20. Also did not work inside the function, however, it does outside.
I dont really know what you are trying to acheive, but I wpuld say that the use of exists in this context is wrong. There is no way that the x cannot exist inside the function. See this example
# All this does is report if x exists
f <- function(x){
if(exists("x"))
cat("Found x!", fill = TRUE)
}
f()
f("a")
f(iris)
# All will be found!
Investigate file.exists instead? This is vectorised, so a vector of files can be investigated at the same time.
The question that you are asking is less trivial than you seem to believe. There are two points that should be addressed to obtain the desired behavior, and especially the first one is somewhat tricky:
As pointed out by #NJBurgo and #KonradRudolph the variable x will always exist within the function since it is an argument of the function. In your case the function exists() should therefore not check whether the variable x is defined. Instead, it should be used to verify whether a variable with a name corresponding to the character string stored in x exists.
This is achieved by using a combination of deparse() and
substitute():
if (exists(deparse(substitute(x)))) { …
Since x is defined only within the scope of the function, the superassignment operator <<- would be required to make a value assigned to x visible outside the function, as suggested by #thothai. However, functions should not have such side effects. Problems with this kind of programming include possible conflicts with another variable named x that could be defined in a different context outside the function body, as well as a lack of clarity concerning the operations performed by the function.
A better way is to return the value instead of assigning it to a variable.
Combining these two aspects, the function could be rewritten like this:
FileAssignment <- function(x){
if (exists(deparse(substitute(x)))) {
print("yes!")
return(parse.vdjtools(x))
} else {
print("Nope!")
return(NULL)}
}
In this version of the function, the scope of x is limited to the function body and the function has no side effects. The return value of FileAssignment(a) is either parse.vdjtools(a) or NULL, depending on whether a exists or not.
Outside the function, this value can be assigned to x with
x <- FileAssignment(a)
Is there an equivalent to method_missing for R?
In other words, is it possible to intercept a call to an nonexistent method on an object and do something with it?
Examples for all types of classes would be great (S3, S4, reference classes).
What I want to do is build an object a so that something like a$b would be possible without having to define b explicitly.
Edit: This is approximately how I would like my object to behave:
setClass("myClass", representation(url = "character"))
a <- new("myClass", url = "http://www.example.com")
a$b$c
# => 'http://www.example.com/b/c'
This is S4 classes but any implementation suggestion is welcome.
regards Oskar
For the access a$b, yes, this is possible – if messy. The reason is that $ is just an operator that we can redefine.
The default definition can be retrieved as follows:
> `$`
.Primitive("$")
It’s easy enough possible to change this so that we first test whether the b in a$b actually exists. Here’s a rough outline (but only a rough outline, see below):
`$` <- function (a, b) {
if (exists(as.character(substitute(b)), where = a))
.Primitive("$")(a, b)
else
methodMissing(as.character(substitute(a)), as.character(substitute(b)))
}
… now we just need to supply methodMissing:
methodMissing <- function (a, b)
cat(sprintf('Requested missing %s on %s\n', b, a))
… and we can use it:
> foo <- list(bar = 'Hello')
> foo$bar
[1] "hello"
> foo$baz
Requested missing baz on foo
However, note that this breaks in interesting ways for other types – for instance, it no longer works with data frames:
> cars$speed
NULL
I don’t know whether it’s trivial to fix this – it’s not enough to test for is.list(a), for instance – so proceed with caution.
The solutions for S3 and S4 are left as an exercise for the reader (actually, I have no clue – I don’t use S4 and rarely use S3).
tryCatch should be the equivalent of method_missing, if I've understood your question properly:
tryCatch(foo(options, named=option1,...), EXCEPTION-CLAUSE-HERE)
I would like to find all functions in a package that use a function. By functionB "using" functionA I mean that there exists a set of parameters such that functionA is called when functionB is given those parameters.
Also, it would be nice to be able to control the level at which the results are reported. For example, if I have the following:
outer_fn <- function(a,b,c) {
inner_fn <- function(a,b) {
my_arg <- function(a) {
a^2
}
my_arg(a)
}
inner_fn(a,b)
}
I might or might not care to have inner_fn reported. Probably in most cases not, but I think this might be difficult to do.
Can someone give me some direction on this?
Thanks
A small step to find uses of functions is to find where the function name is used. Here's a small example of how to do that:
findRefs <- function(pkg, fn) {
ns <- getNamespace(pkg)
found <- vapply(ls(ns, all.names=TRUE), function(n) {
f <- get(n, ns)
is.function(f) && fn %in% all.names(body(f))
}, logical(1))
names(found[found])
}
findRefs('stats', 'lm.fit')
#[1] "add1.lm" "aov" "drop1.lm" "lm" "promax"
...To go further you'd need to analyze the body to ensure it is a function call or the FUN argument to an apply-like function or the f argument to Map etc... - so in the general case, it is nearly impossible to find all legal references...
Then you should really also check that getting the name from that function's environment returns the same function you are looking for (it might use a different function with the same name)... This would actually handle your "inner function" case.
(Upgraded from a comment.) There is a very nice foodweb function in Mark Bravington's mvbutils package with a lot of this capability, including graphical representations of the resulting call graphs. This blog post gives a brief description.
I'd like to give a params argument to a function and then attach it so that I can use a instead of params$a everytime I refer to the list element a.
run.simulation<-function(model,params){
attach(params)
#
# Use elements of params as parameters in a simulation
detach(params)
}
Is there a problem with this? If I have defined a global variable named c and have also defined an element named c of the list "params" , whose value would be used after the attach command?
Noah has already pointed out that using attach is a bad idea, even though you see it in some examples and books. There is a way around. You can use "local attach" that's called with. In Noah's dummy example, this would look like
with(params, print(a))
which will yield identical result, but is tidier.
Another possibility is:
run.simulation <- function(model, params){
# Assume params is a list of parameters from
# "params <- list(name1=value1, name2=value2, etc.)"
for (v in 1:length(params)) assign(names(params)[v], params[[v]])
# Use elements of params as parameters in a simulation
}
Easiest way to solve scope problems like this is usually to try something simple out:
a = 1
params = c()
params$a = 2
myfun <- function(params) {
attach(params)
print(a)
detach(params)
}
myfun(params)
The following object(s) are masked _by_ .GlobalEnv:
a
# [1] 1
As you can see, R is picking up the global attribute a here.
It's almost always a good idea to avoid using attach and detach wherever possible -- scope ends up being tricky to handle (incidentally, it's also best to avoid naming variables c -- R will often figure out what you're referring to, but there are so many other letters out there, why risk it?). In addition, I find code using attach/detach almost impossible to decipher.
Jean-Luc's answer helped me immensely for a case that I had a data.frame Dat instead of the list as specified in the OP:
for (v in 1:ncol(Dat)) assign(names(Dat)[v], Dat[,v])