Hello, I want to call a function "fx" given by name, where some "global" variables (in the environment of fx) are passed to the function. For compatibility reasons I cannot modify the parameter list of fx and I want to avoid setting variables in the global environment (e.g. via <<-) Is there a way, how to do this? Thomas P. The example: fx <- function(y) print(x*y) f <- function(fun, xx) { fxx <- function() {do.call(fun, list(y=3))} x <- x fxx() } f("fx", 13) ## does not work, because fx does not find x
Try this: x <- 7 fx <- function(y) print(x*y) f <- function(fun, x) { myfx <- eval(parse(text=deparse(fun))) myfx(3) } f(fx,2) # uses 2, not 7, for x This creates a new function myfx which has the same functionality as fx but is created in the body of f and therefore has that body as its environment -- with the result that it finds the x arg to f. myfx is not fx (it just has the same functionality) so fx's environment is irrelevant. Just one caveat. If fx is recursive it should use Recall to call itself. See ?Recall --- Hello, I want to call a function "fx" given by name, where some "global" variables (in the environment of fx) are passed to the function. For compatibility reasons I cannot modify the parameter list of fx and I want to avoid setting variables in the global environment (e.g. via <<-) Is there a way, how to do this? Thomas P. The example: fx <- function(y) print(x*y) f <- function(fun, xx) { fxx <- function() {do.call(fun, list(y=3))} x <- x fxx() } f("fx", 13) ## does not work, because fx does not find x
The reason in your example that fx() doesn't find 'x' is that the lexical scope of fx() does not include 'x'. So, this is what must be fixed, in one way or another. One simple way to make your example work is to define fx() in a place where its lexical scope includes the variables you want it to see: > f <- function(fun, xx) { + x <- xx + fxx <- function() do.call(fun, list(y=3)) + fx <- function(y) print(x*y) + fxx() + } > x # verify that x is not a global variable! Error: Object "x" not found > f("fx", 13) [1] 39 > Another way, that is probably more suited to what you want (since it sounds like you don't have control over where fx() is defined), is to make a local copy of fx(), and change its environment: > fx <- function(y) print(x*y) > > f <- function(fun, xx) { + x <- xx + fxx <- function() do.call(fun, list(y=3)) + fx <- fx + environment(fx) <- environment() + fxx() + } > x # verify that x is not a global variable! Error: Object "x" not found > f("fx", 13) [1] 39 > I suspect there is also some way to do this using eval() and its envir= and/or enclos= arguments, but I couldn't get anything like this to work. The above solutions were generated by manual genetic programming (i.e., trial and error), so they may not be particularly good or elegant. However, I'm sure that others will point out both any problems with these suggestions and some better solutions! hope this helps, Tony Plate At Wednesday 09:05 AM 3/10/2004, Thomas Petzoldt wrote:>Hello, > >I want to call a function "fx" given by name, where some "global" >variables (in the environment of fx) are passed to the function. For >compatibility reasons I cannot modify the parameter list of fx and I want >to avoid setting variables in the global environment (e.g. via <<-) > >Is there a way, how to do this? > >Thomas P. > >The example: > >fx <- function(y) print(x*y) > >f <- function(fun, xx) { > fxx <- function() {do.call(fun, list(y=3))} > x <- x > fxx() >} > >f("fx", 13) > >## does not work, because fx does not find x > >______________________________________________ >R-help at stat.math.ethz.ch mailing list >https://www.stat.math.ethz.ch/mailman/listinfo/r-help >PLEASE do read the posting guide! http://www.R-project.org/posting-guide.html
Seems to me what you want is dynamic scoping: `x' is not defined in `fx'. You want `x' to be found in the scope of the function(s) that calls `fx', rather than the environment where `fx' is defined. I was told (thanks, Robert!) that that is a very bad idea: as the author of `fx', you want some assurance of what `x' might be. This is done via R's lexical scope. With dynamic scope, there is absolutely no way to do that. For example, I might write a function `g' that define `x' as a character, or a data frame, or a list, or an `lm' object, or a connection, .... How would you write `fx' to deal with that nightmare if you have dynamic scope? Andy> From: Thomas Petzoldt > > Hello, > > I want to call a function "fx" given by name, where some "global" > variables (in the environment of fx) are passed to the function. For > compatibility reasons I cannot modify the parameter list of fx and I > want to avoid setting variables in the global environment > (e.g. via <<-) > > Is there a way, how to do this? > > Thomas P. > > The example: > > fx <- function(y) print(x*y) > > f <- function(fun, xx) { > fxx <- function() {do.call(fun, list(y=3))} > x <- x > fxx() > } > > f("fx", 13) > > ## does not work, because fx does not find x > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://www.stat.math.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide! > http://www.R-project.org/posting-guide.html > >------------------------------------------------------------------------------ Notice: This e-mail message, together with any attachments,...{{dropped}}
Tony, I played with your solution some more and found that it can be reduced to: fx <- function(y) print(x*y) f <- function(fun, x) { environment(fun) <- environment() fun(3) } f(fx,2) --- Date: Wed, 10 Mar 2004 10:56:28 -0700 From: Tony Plate <tplate at blackmesacapital.com> To: <petzoldt at rcs.urz.tu-dresden.de>,R-Help <r-help at stat.math.ethz.ch> Subject: Re: [R] do.call and environments The reason in your example that fx() doesn't find 'x' is that the lexical scope of fx() does not include 'x'. So, this is what must be fixed, in one way or another. One simple way to make your example work is to define fx() in a place where its lexical scope includes the variables you want it to see:> f <- function(fun, xx) {+ x <- xx + fxx <- function() do.call(fun, list(y=3)) + fx <- function(y) print(x*y) + fxx() + }> x # verify that x is not a global variable!Error: Object "x" not found> f("fx", 13)[1] 39>Another way, that is probably more suited to what you want (since it sounds like you don't have control over where fx() is defined), is to make a local copy of fx(), and change its environment:> fx <- function(y) print(x*y) > > f <- function(fun, xx) {+ x <- xx + fxx <- function() do.call(fun, list(y=3)) + fx <- fx + environment(fx) <- environment() + fxx() + }> x # verify that x is not a global variable!Error: Object "x" not found> f("fx", 13)[1] 39>I suspect there is also some way to do this using eval() and its envir= and/or enclos= arguments, but I couldn't get anything like this to work. The above solutions were generated by manual genetic programming (i.e., trial and error), so they may not be particularly good or elegant. However, I'm sure that others will point out both any problems with these suggestions and some better solutions! hope this helps, Tony Plate At Wednesday 09:05 AM 3/10/2004, Thomas Petzoldt wrote:>Hello, > >I want to call a function "fx" given by name, where some "global" >variables (in the environment of fx) are passed to the function. For >compatibility reasons I cannot modify the parameter list of fx and I want >to avoid setting variables in the global environment (e.g. via <<-) > >Is there a way, how to do this? > >Thomas P. > >The example: > >fx <- function(y) print(x*y) > >f <- function(fun, xx) { > fxx <- function() {do.call(fun, list(y=3))} > x <- x > fxx() >} > >f("fx", 13) > >## does not work, because fx does not find x >
Tony, Thanks very much for the correction. I agree completely. The real nightmare is in not being able to ensure which object, if there can be several of the same name within the scope, that the code is going to pickup. With lexical scope, the developer has the responsibility and control over that, but not with dynamic scope. Best, Andy> From: Tony Plate > > Andy, I think you're correct that Thomas Petzoldt wants > dynamic scoping, but > isn't your argument here about strong typing vs weak typing? To > paraphrase, one > could say: For example, if weak typing were allowed I might write a > function `g' that > passes argument `x' to fx() as a character, or a data frame, > or a list, or > an `lm' object, > or a connection, .... How would you write fx() to deal with > that nightmare > if you have > weak typing? (Actually, the S language does have weak typing, > and some > functions > deal with the "nightmare" by checking the types of their > arguments. Other > functions > just pass their arguments along without type checking, > resulting in cryptic > error > messages). > > I think the issues around lexical vs dynamic scope are more > to do with dynamic > scope making programming accidents more likely, because of > the risk that > a variable in a higher frame is masked unintentionally by > another variable of > the same name in an intervening frame, and more difficult to > track down, > because the error can depend on the exact calling sequence > when it occurred. > > cheers, > > Tony Plate > > At Wednesday 11:03 AM 3/10/2004, Liaw, Andy wrote: > >Seems to me what you want is dynamic scoping: `x' is not > defined in `fx'. > >You want `x' to be found in the scope of the function(s) > that calls `fx', > >rather than the environment where `fx' is defined. I was > told (thanks, > >Robert!) that that is a very bad idea: as the author of > `fx', you want some > >assurance of what `x' might be. This is done via R's > lexical scope. With > >dynamic scope, there is absolutely no way to do that. For > example, I might > >write a function `g' that define `x' as a character, or a > data frame, or a > >list, or an `lm' object, or a connection, .... How would > you write `fx' to > >deal with that nightmare if you have dynamic scope? > > > >Andy > > > > > From: Thomas Petzoldt > > > > > > Hello, > > > > > > I want to call a function "fx" given by name, where some "global" > > > variables (in the environment of fx) are passed to the > function. For > > > compatibility reasons I cannot modify the parameter list > of fx and I > > > want to avoid setting variables in the global environment > > > (e.g. via <<-) > > > > > > Is there a way, how to do this? > > > > > > Thomas P. > > > > > > The example: > > > > > > fx <- function(y) print(x*y) > > > > > > f <- function(fun, xx) { > > > fxx <- function() {do.call(fun, list(y=3))} > > > x <- x > > > fxx() > > > } > > > > > > f("fx", 13) > > > > > > ## does not work, because fx does not find x > > > > > > ______________________________________________ > > > R-help at stat.math.ethz.ch mailing list > > > https://www.stat.math.ethz.ch/mailman/listinfo/r-help > > > PLEASE do read the posting guide! > > > http://www.R-project.org/posting-guide.html > > > > > > > > > > > >------------------------------------------------------------- > ----------------- > >Notice: This e-mail message, together with any > attachments,...{{dropped}} > > > >______________________________________________ > >R-help at stat.math.ethz.ch mailing list > >https://www.stat.math.ethz.ch/mailman/listinfo/r-help > >PLEASE do read the posting guide! > http://www.R-project.org/posting-guide.html > > > ______________________________________________ > R-help at stat.math.ethz.ch mailing list > https://www.stat.math.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide! > http://www.R-project.org/posting-guide.html > >------------------------------------------------------------------------------ Notice: This e-mail message, together with any attachments,...{{dropped}}