Function with extra parameters from another function's input - r

This is a relatively simply problem but I'm stumped. I am programming in R, but I don't think this problem is restricted to R. Below I've tried to write some simple code demonstrating the problem:
f1 = function(x) {
return(a + x)
}
f2 = function(ftn) {
return(ftn(1))
}
f3 = function(a) {
return(f2(f1))
}
The Problem: If I call f3(2) [for example], f2(f1) is returned, and f2(f1) returns f1(a+1). But f1 does not recognize the value of 'a' that I put in f3, so the code doesn't work! Is there any way I can make it so that f1 recognizes the input into f3?

R uses lexical scope, not dynamic scope. Functions look up free variables (variables used but not defined within them) in the environment in which the function was defined. f1 was defined in the global environment so a is looked up in the global environment and there is no a there. We can force f1 to look up its free variables in the running instance of f3 like this:
f3 = function(a) {
environment(f1) <- environment()
return(f2(f1))
}
This temporarily creates a new f1 within f3 with the desired environment.
Another possibility if f1 is only needed within f3 is to define f1 there (rather than in the global environment):
f3 = function(a) {
f1 = function(x) {
return(a + x)
}
return(f2(f1))
}
By the way, the last expression evaluated in a running function is returned so this could be written:
f3 <- function(a) {
f1 <- function(x) a + x
f2(f1)
}

Related

curve3d can't find local function "fn"

I'm trying to use the curve3d function in the emdbook-package to create a contour plot of a function defined locally inside another function as shown in the following minimal example:
library(emdbook)
testcurve3d <- function(a) {
fn <- function(x,y) {
x*y*a
}
curve3d(fn(x,y))
}
Unexpectedly, this generates the error
> testcurve3d(2)
Error in fn(x, y) : could not find function "fn"
whereas the same idea works fine with the more basic curve function of the base-package:
testcurve <- function(a) {
fn <- function(x) {
x*a
}
curve(a*x)
}
testcurve(2)
The question is how curve3d can be rewritten such that it behaves as expected.
You can temporarily attach the function environment to the search path to get it to work:
testcurve3d <- function(a) {
fn <- function(x,y) {
x*y*a
}
e <- environment()
attach(e)
curve3d(fn(x,y))
detach(e)
}
Analysis
The problem comes from this line in curve3d:
eval(expr, envir = env, enclos = parent.frame(2))
At this point, we appear to be 10 frames deep, and fn is defined in parent.frame(8). So you can edit the line in curve3d to use that, but I'm not sure how robust this is. Perhaps parent.frame(sys.nframe()-2) might be more robust, but as ?sys.parent warns there can be some strange things going on:
Strictly, sys.parent and parent.frame refer to the context of the
parent interpreted function. So internal functions (which may or may
not set contexts and so may or may not appear on the call stack) may
not be counted, and S3 methods can also do surprising things.
Beware of the effect of lazy evaluation: these two functions look at
the call stack at the time they are evaluated, not at the time they
are called. Passing calls to them as function arguments is unlikely to
be a good idea.
The eval - parse solution bypasses some worries about variable scope. This passes the value of both the variable and function directly as opposed to passing the variable or function names.
library(emdbook)
testcurve3d <- function(a) {
fn <- eval(parse(text = paste0(
"function(x, y) {",
"x*y*", a,
"}"
)))
eval(parse(text = paste0(
"curve3d(", deparse(fn)[3], ")"
)))
}
testcurve3d(2)
I have found other solution that I do not like very much, but maybe it will help you.
You can create the function fn how a call object and eval this in curve3d:
fn <- quote((function(x, y) {x*y*a})(x, y))
eval(call("curve3d", fn))
Inside of the other function, the continuous problem exists, a must be in the global environment, but it is can fix with substitute.
Example:
testcurve3d <- function(a) {
fn <- substitute((function(x, y) {
c <- cos(a*pi*x)
s <- sin(a*pi*y/3)
return(c + s)
})(x, y), list(a = a))
eval(call("curve3d", fn, zlab = "fn"))
}
par(mfrow = c(1, 2))
testcurve3d(2)
testcurve3d(5)

Why is this simple function not working?

I first defined new variable x, then created function that require x within its body (not as argument). See code below
x <- c(1,2,3)
f1 <- function() {
x^2
}
rm(x)
f2 <- function() {
x <- c(1,2,3)
f1()
}
f(2)
Error in f1() : object 'x' not found
When I removed x, and defined new function f2 that first define x and then execute f1, it shows objects x not found.
I just wanted to know why this is not working and how I can overcome this problem. I do not want x to be name as argument in f1.
Please provide appropriate title because I do not know what kind of problem is this.
You could use a closure to make an f1 with the desired properties:
makeF <- function(){
x <- c(1,2,3)
f1 <- function() {
x^2
}
f1
}
f1 <- makeF()
f1() #returns 1 4 9
There is no x in the global scope but f1 still knows about the x in the environment that it was defined in.
In short: Your are expecting dynamic scoping but are a victim of R's lexical scoping:
dynamic scoping = the enclosing environment of a command is determined during run-time
lexical scoping = the enclosing environment of a command is determined at "compile time"
To understand the lookup path of your variable x in the current and parent environments try this code.
It shows that both functions do not share the environment in with x is defined in f2 so it can't never be found:
# list all parent environments of an environment to show the "search path"
parents <- function(env) {
while (TRUE) {
name <- environmentName(env)
txt <- if (nzchar(name)) name else format(env)
cat(txt, "\n")
if (txt == "R_EmptyEnv") break
env <- parent.env(env)
}
}
x <- c(1,2,3)
f1 <- function() {
print("f1:")
parents(environment())
x^2
}
f1() # works
# [1] "f1:"
# <environment: 0x4ebb8b8>
# R_GlobalEnv
# ...
rm(x)
f2 <- function() {
print("f2:")
parents(environment())
x <- c(1,2,3)
f1()
}
f2() # does not find "x"
# [1] "f2:"
# <environment: 0x47b2d18>
# R_GlobalEnv
# ...
# [1] "f1:"
# <environment: 0x4765828>
# R_GlobalEnv
# ...
Possible solutions:
Declare x in the global environment (bad programming style due to lack of encapsulation)
Use function parameters (this is what functions are made for)
Use a closure if x has always the same value for each call of f1 (not for beginners). See the other answer from #JohnColeman...
I strongly propose using 2. (add x as parameter - why do you want to avoid this?).

Passing variables through environments

I have the following two functions :
f1<-function(){
txt<-1234
f2(where="txt")
}
f2<-function(where){
foo<-eval(parse(text = where))*2
return(foo)
}
When calling f1(), I would expect it to return 2468. However
> f1()
Error in eval(expr, envir, enclos) : object 'txt' not found
I do not understand why, and specifically why f2 does not know txt. Of course it is not defined in its own environment, but it is defined in the caller environment (in f1), I thought everything defined within f1 should be visible to f2 ?
Of course, if in f1 I have
txt<<-1234
then
> f1()
[1] 2468
But I would rather avoid global assignments (in real code, I do not want to have stray global objects...)
So the question is, how can I make txt (defined in f1) visible to f2 ?
Thanks
(and in case you wonder, the real-life f2 is more complex, such that passing the name of a variable makes sense; in any case it is a function written by somebody else on which I have no control, so the solution should come from the f1 side).
1) The problem is really with f2, not with f1, so f2 should be fixed. One would normally define f2 to pass the environment explicitly. With this code f1 would work as is.
f2 <- function(where, envir = parent.frame()) {
eval(parse(text = where), envir = envir)*2` .
}
2) The following is less desirable; however, if we did not have control over f2 then we could do this in f1 (where now f2 is unchanged from the question):
f1 <- function() {
txt <- 1234
environment(f2) <- environment()
f2(where = "txt")
}
3) A third option is to define f2 within f1:
f1 <- function(){
f2 <- function(where) eval(parse(text = where))*2
txt <- 1234
f2(where = "txt")
}
f1()
Specify the envir argument in eval as parent.frame()
f2<-function(where){
foo<-eval(parse(text = where), envir= parent.frame())*2
return(foo)
}
f1()
#[1] 2468

What are the benefits of defining and calling a function inside another function in R?

Approach 1
f1 <- function(x)
{
# Do calculation xyz ....
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
return(f2(x))
}
Approach 2
f2 <- function(y)
{
# Do stuff...
return(some_object)
}
f3 <- function(x)
{
# Do calculation xyz ....
return(f2(x))
}
Assume f1 and f3 both do the same calculations and give the same result.
Are there any significant advantages in using approach 1, calling f1(), vs approach 2, calling f3()?
Is a certain approach more favourable when:
large data is being passed in and/or out of f2?
Speed is a big issue. E.g. f1 or f3 are called repeatedly in simulations.
(Approach 1 seems common in packages, defining inside another)
One advantage of using the approach f1 is that f2 won't exist outside f1 once f1 has finished being called (and f2 is only called in f1 or f3).
Benefits of defining f2 inside f1:
f2 only visible within f1, useful if f2 is only meant for use within f1, though within package namespaces this is debatable since you just wouldn't export f2 if you defined it outside
f2 has access to variables within f1, which could be considered a good or a bad thing:
good, because you don't have to pass variables through the function interface and you can use <<- to implement stuff like memoization, etc.
bad, for the same reasons...
Disadvantages:
f2 needs to be redefined every time you call f1, which adds some overhead (not very much overhead, but definitely there)
Data size should not matter since R won't copy the data unless it is being modified under either scenario. As noted in disadvantages, defining f2 outside of f1 should be a little faster, especially if you are repeating an otherwise relatively low overhead operation many times. Here is an example:
> fun1 <- function(x) {
+ fun2 <- function(x) x
+ fun2(x)
+ }
> fun2a <- function(x) x
> fun3 <- function(x) fun2a(x)
>
> library(microbenchmark)
> microbenchmark(
+ fun1(TRUE), fun3(TRUE)
+ )
Unit: nanoseconds
expr min lq median uq max neval
fun1(TRUE) 656 674.5 728.5 859.5 17394 100
fun3(TRUE) 406 434.5 480.5 563.5 1855 100
In this case we save 250ns (edit: the difference is actually 200ns; believe it or not the extra set of {} that fun1 has costs another 50ns). Not much, but can add up if the interior function is more complex or you repeat the function many many times.
You would typically use approach 2. Some exceptions are
Function closures:
f = function() {
counter = 1
g = function() {
counter <<- counter + 1
return(counter)
}
}
counter = f()
counter()
counter()
Function closure enable us to remember the state.
Sometimes it's handy to only define functions as they are only used in one place. For example, when using optim, we often tweak an existing function. For example,
pdf = function(x, mu) dnorm(x, mu, log=TRUE)
f = function(d, lower, initial=0) {
ll = function(mu) {
if(mu < lower) return(-Inf)
else -sum(pdf(d, mu))
}
optim(initial, ll)
}
f(d, 1.5)
The ll function uses the data set d and a lower bound. This is both convenient since this may be the only time we use/need the ll function.
An example of what is mentioned in existing answers is probably what I now think of as being the most useful benefit of defining a function in the environment of another function. In simple terms: You can define functions without specifying all the parameters used inside it, provided those parameters are defined somewhere in the environment in which the function is defined. A nice reference for function environments is of course: https://adv-r.hadley.nz/environments.html
This approach can be handy for breaking up blocks of code in a function, where multiple variables might be required and referred to within the function body, into a bunch of sub functions in the function's environment, allowing for cleaner representation of the code, without having to write out a potentially long parameter list.
A simple dummy example below highlights the point
f1 <- function(x)
{
f2 <- function(y)
{
# possibly long block of code relevant to the meaning of what `f2` represents
y + a + b + d
}
# might be 10+ variables in special cases
a <- 10
b <- 5
d <- 1
f2(x)
}
#test:
> f1(100)
[1] 116
You can't use this approach if you define the functions with separate parent environments:
f3 <- function(x)
{
a <- 10
b <- 5
d <- 1
f2a(x)
}
f2a <- function(y)
{
y + a + b + d
}
> f3(100)
Error in f2a(x) : object 'a' not found

R function which returns a function... and variable scope

I am learning about functions returning other functions. For example:
foo1 <- function()
{
bar1 <- function()
{
return(constant)
}
}
foo2 <- function()
{
constant <- 1
bar2 <- function()
{
return(constant)
}
}
Suppose, now, I declare functions f1 and f2 as follows:
constant <- 2
f1 <- foo1()
f2 <- foo2()
Then it appears they have the same function definition:
> f1
function()
{
return(constant)
}
<environment: 0x408f048>
> f2
function()
{
return(constant)
}
<environment: 0x4046d78>
>
BUT the two functions are different. For example:
> constant <- 2
> f1()
[1] 2
> f2()
[1] 1
My question: Why is it legal for two functions, with identical function definitions, to produce different results?
I understand that foo1 treats constant as a global variable and foo2 as a constant variable, but it is impossible to tell this from the function definition surely?
(I am probably missing something fundamental.)
Sure they're different, the environments are different. Try ls(environment(f1)) and then ls(environment(f2)) and then get('constant', environment (f1)) and same for f2
Scope in R
Lev's answer is correct. To describe in more detail. When you you call f1 or pass f1 around you also have a reference to the original lexical environment in which the function was defined.
#since R is interpreted.. the variable constant doesn't have to be defined in the lexical environment... this all gets checked and evaluated at runtime
foo1ReturnedThisFunction <- foo1()
#outputs "Error in foo1ReturnedThisFunction() : object 'constant' not found"
foo1ReturnedThisFunction()
#defined the variable constant in the lexical environment
constant <- 5
#outputs 5
foo1ReturnedThisFunction()
in foo2... there is a definition of the variable constant in the "closer" (not sure if this is the right term) lexical environment so it uses that and doesn't look for the variable constant in the "global" environment

Resources