To use the modify the solution from Tony and I
so that you can pass the name of the function, rather
than the function itself, like this:
x <- 7
fx <- function(y) print(x*y)
f <- function(fun, x) {
fun <- get(fun)
environment(fun) <- environment()
do.call("fun",list(3))
}
f("fx",2)
---
Date: Thu, 11 Mar 2004 08:22:45 +0100
From: Thomas Petzoldt <petzoldt at rcs.urz.tu-dresden.de>
Cc: <petzoldt at rcs.urz.tu-dresden.de>, <r-help at
stat.math.ethz.ch>
Subject: [R] Summary: do.call and environments
Dear R users,
thank you very much for your suggestions. I've learned much, especially
that the problem was not as simple as I thought. There have been several
proposals, but most of them solved the problem only partly.
The proposal(s) of Gabor and Tony (different versions) seemed to be very
promising:
> fx <- function(y) print(x*y)
> f <- function(fun, x) {
> environment(fun) <- environment()
> fun(3)
> }
> f(fx,2)
... but unfortunately they miss the "do.call" mechanism. I intended to
call a function given as character with f("fx", value), and not f(fx,
value).
Another proposal (from Robert Gentleman, thank you) works. It has the
only disadvantage, that I have to set an environment outside of my own
function. If I understand this correctly, this means that the new
environment ist set persistently (*globally*) and may have side-effects
to other calls:
> fx <- function(y) print(x*y)
> environment(fx) <- new.env()
>
> ff <- function(fun, x) {
> assign("x", x, environment(get(fun, mode="function")))
> do.call(fun, list(y=3))
> }
Furthermore, Andy pointed out that my idea was a bad one, but why I am
trying such weired things? My problem is, that I want to define list
objects which contain informations, about how they are processed (as
character, not as copy of a function). This solver function (e.g.
"lsoda" from the odesolve package) then calls a third function (my
model
equations), provided from my side again, but unfortunately does not
"pass through" some additonal argument(s), needed by the model
equations. So I wanted to call lsoda or my own function provided with
the additional arguments within an own environment.
Now, as it comes out, that this was really a bad idea, I should focus on
the pass-trough method (...) and use one of the 99% workarounds
mentioned above in the meantime.
Thank you again
Thomas P.
That looks great, but I'm confused. In R 1.8.1 under Windows
2000, the suggested script produced for me the following:
> f("fx",2)
[1] 6
I would have naively expected 14. From whence cometh "6"?
Also, I prefer to use transportable code wherever feasible. The
same script generated the following response from S-Plus 6.2:
> f("fx", 2)
Problem in f("fx", 2): Couldn't find a function definition for
"environment"
Use traceback() to see the call stack
Thanks,
Spencer Graves
Gabor Grothendieck wrote:
>To use the modify the solution from Tony and I
>so that you can pass the name of the function, rather
>than the function itself, like this:
>
>x <- 7
>fx <- function(y) print(x*y)
>f <- function(fun, x) {
> fun <- get(fun)
> environment(fun) <- environment()
> do.call("fun",list(3))
>}
>f("fx",2)
>
>
>---
>Date: Thu, 11 Mar 2004 08:22:45 +0100
>From: Thomas Petzoldt <petzoldt at rcs.urz.tu-dresden.de>
>Cc: <petzoldt at rcs.urz.tu-dresden.de>, <r-help at
stat.math.ethz.ch>
>Subject: [R] Summary: do.call and environments
>
>
>Dear R users,
>
>thank you very much for your suggestions. I've learned much, especially
>that the problem was not as simple as I thought. There have been several
>proposals, but most of them solved the problem only partly.
>
>The proposal(s) of Gabor and Tony (different versions) seemed to be very
>promising:
>
>
>
>>fx <- function(y) print(x*y)
>>f <- function(fun, x) {
>>environment(fun) <- environment()
>>fun(3)
>>}
>>f(fx,2)
>>
>>
>
>... but unfortunately they miss the "do.call" mechanism. I
intended to
>call a function given as character with f("fx", value), and not
f(fx,
>value).
>
>Another proposal (from Robert Gentleman, thank you) works. It has the
>only disadvantage, that I have to set an environment outside of my own
>function. If I understand this correctly, this means that the new
>environment ist set persistently (*globally*) and may have side-effects
>to other calls:
>
>
>
>>fx <- function(y) print(x*y)
>>environment(fx) <- new.env()
>>
>>ff <- function(fun, x) {
>>assign("x", x, environment(get(fun,
mode="function")))
>>do.call(fun, list(y=3))
>>}
>>
>>
>
>Furthermore, Andy pointed out that my idea was a bad one, but why I am
>trying such weired things? My problem is, that I want to define list
>objects which contain informations, about how they are processed (as
>character, not as copy of a function). This solver function (e.g.
>"lsoda" from the odesolve package) then calls a third function (my
model
>equations), provided from my side again, but unfortunately does not
>"pass through" some additonal argument(s), needed by the model
>equations. So I wanted to call lsoda or my own function provided with
>the additional arguments within an own environment.
>
>Now, as it comes out, that this was really a bad idea, I should focus on
>the pass-trough method (...) and use one of the 99% workarounds
>mentioned above in the meantime.
>
>Thank you again
>
>Thomas P.
>
>______________________________________________
>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
>
>
>
Note that R and S are fundamentally different when it comes to
scoping.
R uses lexical scoping, i.e. the parent environment of a function
is the environment at the point where it is *defined* whereas
S uses dynamic scoping, i.e. the parent environment in a function
is the environment at the point where the function is *called*.
Thus, anything regarding scoping will be different in the
two systems.
Note that in S, the question is easy since all you need is:
x <- 7
fx <- function(y) print(x*y)
f <- function(fx, x) do.call(fx,list(3))
f("fx",2)
This gives 6 in S but 21 in R. (Better check this since I
don't have access to S and am going by my understanding.)
In fact, this entire exercise can be regarded as simulating
S-style dynamic scoping in R.
---
Date: Thu, 11 Mar 2004 09:45:32 +0100
From: Thomas Petzoldt <petzoldt at rcs.urz.tu-dresden.de>
To: Spencer Graves <spencer.graves at pdf.com>
Cc: <ggrothendieck at myway.com>, <r-help at stat.math.ethz.ch>
Subject: Re: [R] Summary: do.call and environments
Hello,
> > f("fx",2)
> [1] 6
>
> I would have naively expected 14. From whence cometh "6"?
> Also, I prefer to use transportable code wherever feasible. The
2*3=6, which was the intention. It is in fact only a proof of
correctness, that "7" is not used here. The proposal of Gabor does
exactly, what I want, but if it does not work on S-PLUS, it's a serious
disadvantage and I should check this too.
Thomas P.
Gabor,> From: Gabor Grothendieck > > Note that R and S are fundamentally different when it comes to > scoping. > > R uses lexical scoping, i.e. the parent environment of a function > is the environment at the point where it is *defined* whereas > S uses dynamic scoping, i.e. the parent environment in a function > is the environment at the point where the function is *called*.I don't think that's quite right. S does not use dynamic scope. This simple example fails in S-PLUS (6.1):> g <- function() x + y > f <- function() {+ x <- 2 + y <- 3 + g() + }> f()Problem in g(): Object "y" not found Use traceback() to see the call stack It would have worked if S has dynamic scope: variables defined in the caller's (f in this case) frame is visible to the function being called (g in this case). The S scoping rule is described in the S-PLUS programmer's guide, as well as V&R's `S Programming' (which also describes R's lexical scope). And of course, the example doesn't work in R, either:> g <- function() x + y > f <- function() {+ x <- 3 + y <- 2 + g() + }> f()Error in g() : Object "x" not found Cheers, Andy> Thus, anything regarding scoping will be different in the > two systems. > > Note that in S, the question is easy since all you need is: > > x <- 7 > fx <- function(y) print(x*y) > f <- function(fx, x) do.call(fx,list(3)) > f("fx",2) > > This gives 6 in S but 21 in R. (Better check this since I > don't have access to S and am going by my understanding.) > > In fact, this entire exercise can be regarded as simulating > S-style dynamic scoping in R. > > --- > Date: Thu, 11 Mar 2004 09:45:32 +0100 > From: Thomas Petzoldt <petzoldt at rcs.urz.tu-dresden.de> > To: Spencer Graves <spencer.graves at pdf.com> > Cc: <ggrothendieck at myway.com>, <r-help at stat.math.ethz.ch> > Subject: Re: [R] Summary: do.call and environments > > > Hello, > > > > f("fx",2) > > [1] 6 > > > > I would have naively expected 14. From whence cometh "6"? > > Also, I prefer to use transportable code wherever feasible. The > > 2*3=6, which was the intention. It is in fact only a proof of > correctness, that "7" is not used here. The proposal of Gabor does > exactly, what I want, but if it does not work on S-PLUS, it's > a serious > disadvantage and I should check this too. > > Thomas P. > > ______________________________________________ > 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}}
It is possible to fake something very like dynamic scoping
in S-PLUS as in the following example:
fx <- function(y) print(get("x", inherit=T) * y)
fxx <- function(fun,x) fun(3)
fxx(fx,2)
[1] 6
As several posters already pointed out; this strategy will
not always do what you want (it will pick up the first x defined in
the frames stack, rather than necessarily the x passed to fxx,
in a more complicated nested call) - that's the downside of
dynamic scoping.
In R the above will not do what you want at all; fx will still be
evaluated in the environment in which it was defined, and will
never read the x passed to fxx.
You COULD do this in R:
fx <- function(y) print(get("x", envir=sys.parent()) * y)
but that will only work for fx called from fxx directly - you cannot
set both envir and inherits arguments in R (nor both frame and
inherit in S-PLUS).
But in R you can do (thanks Tony, mod Gabor)
fx <- function(y) print(x*y)
fxx <- function(fun, x) {
environment(fun) <- environment()
fun(3)
}
And that's a lovely example of the power of lexical scoping,
guaranteeing that the x of the fxx call will be used. [Provided
you don't reset the environment again before calling fun, but
why would you ever do that?]
Incidentally, anyone for golf? How about
fxx <- function(fun,x) eval(parse(text=deparse(fun)))(3)
The above won't work in S-PLUS by the way, not even if you
force the eval in sys.parent(). That's the kind of thing that used
to drive me mad in S-PLUS - why, oh why, doesn't it work? [Don't
answer that.]
IMHO there isn't going to be a solution that works in both R and
S-PLUS - now there's asking to be shot down in flames - or if there is,
it would not be natural to either dialect. Scoping is precisely where
R and S-PLUS do not match.
Having said that I wonder if the original poster really needed to
get into this problem at all, what is wrong with
fxy <- function(x,y) print(x*y)
ffxy <- function(fun,x,y) fun(x,y)
ffxy(fxy,2,3)
IE just pass x as an argument. That works in all S.
HTH
Simon
Simon Fear
Senior Statistician
Syne qua non Ltd
Tel: +44 (0) 1379 644449
Fax: +44 (0) 1379 644445
email: Simon.Fear at synequanon.com
web: http://www.synequanon.com
Number of attachments included with this message: 0
This message (and any associated files) is confidential and\...{{dropped}}