After many hours of debugging code, I came to the conclusion that I
have a fundamental misunderstanding regarding eval, and hope that
someone here can explain to me, why the following code acts as it does:
foo <- function(expr) {
eval(substitute(expr), envir=list(a=5), enclos=parent.frame())
}
bar <- function(er) {
foo(er)
}
> foo(a)
[1] 5
> bar(a)
Error in eval(expr, envir, enclos) : object "a" not found
Now, regarding the "bar(a)" call, this is my understanding of what
happens, hoping someone will correct me where I'm wrong.
1) bar is called. Its evaluation frame contains the association "er=a".
2) bar calls foo. So foo is called, and its evaluation frame contains
the association "expr=er", with enclosing environment the local
environment of bar.
3) foo calls eval.
4) eval starts by evaluating "substitute(expr)" in foo's environment.
"substitute" then locates expr in foo's environment, and replaces it
with er. So the result of this process is the symbol er, which is
what will now be evaluated by eval.
5) eval then creates the environment where this evaluation will take
place. It does that by creating an environment containing the frame
"a=5", and with enclosing environment the parent frame of foo, which
is bar's environment.
6) So, as I understand it, the symbol "er" is going to now be
evaluated in an environment where a is set to 5 and er is set to a,
along with whatever is in the user's workspace.
7) So the first step now is looking up a definition for er. Nothing
is found in the current frame, so the evaluation proceeds to bar's
environment, where the association "er=a" is found, so er is replaced
by a.
8) Now, and perhaps this is where I misunderstand things, the lookup
for a will take place. My thinking was that the lookup would start
from the evaluation environment that eval created, and hence would
locate the a=5 value. But this is clearly not what happens.
Anyway, hope someone will correct me where I'm wrong, and explain to
me what I am doing wrong, and ideally how to diagnose such things.
Thanks,
Haris Skiadas
Department of Mathematics and Computer Science
Hanover College
Understanding eval
8 messages · Gabor Grothendieck, Charilaos Skiadas, Duncan Murdoch
On 22/12/2007 3:30 PM, Charilaos Skiadas wrote:
After many hours of debugging code, I came to the conclusion that I
have a fundamental misunderstanding regarding eval, and hope that
someone here can explain to me, why the following code acts as it does:
foo <- function(expr) {
eval(substitute(expr), envir=list(a=5), enclos=parent.frame())
}
bar <- function(er) {
foo(er)
}
> foo(a)
[1] 5
> bar(a)
Error in eval(expr, envir, enclos) : object "a" not found Now, regarding the "bar(a)" call, this is my understanding of what happens, hoping someone will correct me where I'm wrong. 1) bar is called. Its evaluation frame contains the association "er=a". 2) bar calls foo. So foo is called, and its evaluation frame contains the association "expr=er", with enclosing environment the local environment of bar. 3) foo calls eval. 4) eval starts by evaluating "substitute(expr)" in foo's environment. "substitute" then locates expr in foo's environment, and replaces it with er. So the result of this process is the symbol er, which is what will now be evaluated by eval. 5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace.
I think this part is wrong. A better description is: er is going to be evaluated in an environment where a is set to 5. The parent of that environment is the bar evaluation frame, where er is set to be a promise to evaluate a in the global environment.
7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a.
No, at this point an attempt is made to force the promise. Promises have their own associated environments, and that's where the evaluation takes place. In the case of the er object, the associated environment is the one where bar(a) was called, i.e. the global environment.
8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things.
Diagnosing things like this is hard. Promises are very difficult things to look at: as soon as you try to do anything with them they get evaluated, and there's no way in R code to display them without that. You can use substitute() to extract the expression part, but there's no way to extract the environment part. Maybe there should be, but it's tricky to get the semantics right. If the function environment() worked to extract the environment of a promise, then all sorts of code would fail where I really wanted to evaluate the arg before extracting the environment. Duncan Murdoch
On Dec 22, 2007, at 4:44 PM, Duncan Murdoch wrote:
5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace.
I think this part is wrong. A better description is: er is going to be evaluated in an environment where a is set to 5. The parent of that environment is the bar evaluation frame, where er is set to be a promise to evaluate a in the global environment.
7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a.
No, at this point an attempt is made to force the promise. Promises have their own associated environments, and that's where the evaluation takes place. In the case of the er object, the associated environment is the one where bar(a) was called, i.e. the global environment.
8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things.
Diagnosing things like this is hard. Promises are very difficult things to look at: as soon as you try to do anything with them they get evaluated, and there's no way in R code to display them without that. You can use substitute() to extract the expression part, but there's no way to extract the environment part. Maybe there should be, but it's tricky to get the semantics right. If the function environment() worked to extract the environment of a promise, then all sorts of code would fail where I really wanted to evaluate the arg before extracting the environment.
Thank you Duncan, for the very clear explanation.
Ok, so the substitute "breaks through" the promise of expr, returning
as a language object the promise of er, and there's no easy way to
break through that. I ended up with the following, somewhat uglier
than I wanted, code, which seems to do what I need in this case, and
hopefully will still work in the more general case I want it to. The
idea was to break through the er promise in bar, before sending it
over to foo. Then foo receives simply an expression, which it can
then evaluate. Though I seem to have had to work a bit harder on that
part than I expected to. Perhaps there's an easier way? Or things
that can go seriously wrong with this way?
foo <- function(fr, expr) {
..obj <- list(.=fr)
..expr <- substitute(expr)
..txt <- parse( text=paste("substitute(",..expr,")") )
..expr <- eval(..txt, ..obj, parent.frame())
..expr <- eval(..expr, parent.frame())
eval(..expr, ..obj)
}
bar <- function(parent, er, ...) {
.fr=parent
g <- substitute(er)
foo(.fr, g)
}
> foo(5,.)
[1] 5
> bar(5,.)
[1] 5
Duncan Murdoch
Haris Skiadas Department of Mathematics and Computer Science Hanover College
Duncan has already pointed out that consideration of promises is
what is missing in the description but in addition the way lm and
other functions in R get around it is to use match.call like this:
bar2 <- function(er) {
mc <- match.call()
mc[[1]] <- as.name("foo")
names(mc)[[2]] <- "expr"
eval.parent(mc)
}
bar2(a)
On Dec 22, 2007 3:30 PM, Charilaos Skiadas <cskiadas at gmail.com> wrote:
After many hours of debugging code, I came to the conclusion that I
have a fundamental misunderstanding regarding eval, and hope that
someone here can explain to me, why the following code acts as it does:
foo <- function(expr) {
eval(substitute(expr), envir=list(a=5), enclos=parent.frame())
}
bar <- function(er) {
foo(er)
}
> foo(a)
[1] 5
> bar(a)
Error in eval(expr, envir, enclos) : object "a" not found Now, regarding the "bar(a)" call, this is my understanding of what happens, hoping someone will correct me where I'm wrong. 1) bar is called. Its evaluation frame contains the association "er=a". 2) bar calls foo. So foo is called, and its evaluation frame contains the association "expr=er", with enclosing environment the local environment of bar. 3) foo calls eval. 4) eval starts by evaluating "substitute(expr)" in foo's environment. "substitute" then locates expr in foo's environment, and replaces it with er. So the result of this process is the symbol er, which is what will now be evaluated by eval. 5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace. 7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a. 8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things. Thanks, Haris Skiadas Department of Mathematics and Computer Science Hanover College
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
That's a very good idea. I'll have to see if and how it applies to the more general case I'm dealing with. ( Essentially I am trying to create "tkcbind" and "tkrbind" kind of functions, that group together tcltk widgets under a new frame they create, and the frame has to be created before the widgets are and the widgets should be created with the frame as their parent etc. ... ). Anyway, that's another story for another day ;). Haris Skiadas Department of Mathematics and Computer Science Hanover College
On Dec 22, 2007, at 8:51 PM, Gabor Grothendieck wrote:
Duncan has already pointed out that consideration of promises is
what is missing in the description but in addition the way lm and
other functions in R get around it is to use match.call like this:
bar2 <- function(er) {
mc <- match.call()
mc[[1]] <- as.name("foo")
names(mc)[[2]] <- "expr"
eval.parent(mc)
}
bar2(a)
On Dec 22, 2007 3:30 PM, Charilaos Skiadas <cskiadas at gmail.com> wrote:
After many hours of debugging code, I came to the conclusion that I
have a fundamental misunderstanding regarding eval, and hope that
someone here can explain to me, why the following code acts as it
does:
foo <- function(expr) {
eval(substitute(expr), envir=list(a=5), enclos=parent.frame())
}
bar <- function(er) {
foo(er)
}
foo(a)
[1] 5
bar(a)
Error in eval(expr, envir, enclos) : object "a" not found Now, regarding the "bar(a)" call, this is my understanding of what happens, hoping someone will correct me where I'm wrong. 1) bar is called. Its evaluation frame contains the association "er=a". 2) bar calls foo. So foo is called, and its evaluation frame contains the association "expr=er", with enclosing environment the local environment of bar. 3) foo calls eval. 4) eval starts by evaluating "substitute(expr)" in foo's environment. "substitute" then locates expr in foo's environment, and replaces it with er. So the result of this process is the symbol er, which is what will now be evaluated by eval. 5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace. 7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a. 8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things. Thanks, Haris Skiadas Department of Mathematics and Computer Science Hanover College
On 22/12/2007 5:45 PM, Charilaos Skiadas wrote:
On Dec 22, 2007, at 4:44 PM, Duncan Murdoch wrote:
5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace.
I think this part is wrong. A better description is: er is going to be evaluated in an environment where a is set to 5. The parent of that environment is the bar evaluation frame, where er is set to be a promise to evaluate a in the global environment.
7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a.
No, at this point an attempt is made to force the promise. Promises have their own associated environments, and that's where the evaluation takes place. In the case of the er object, the associated environment is the one where bar(a) was called, i.e. the global environment.
8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things.
Diagnosing things like this is hard. Promises are very difficult things to look at: as soon as you try to do anything with them they get evaluated, and there's no way in R code to display them without that. You can use substitute() to extract the expression part, but there's no way to extract the environment part. Maybe there should be, but it's tricky to get the semantics right. If the function environment() worked to extract the environment of a promise, then all sorts of code would fail where I really wanted to evaluate the arg before extracting the environment.
Thank you Duncan, for the very clear explanation.
Ok, so the substitute "breaks through" the promise of expr, returning
as a language object the promise of er, and there's no easy way to
break through that. I ended up with the following, somewhat uglier
than I wanted, code, which seems to do what I need in this case, and
hopefully will still work in the more general case I want it to. The
idea was to break through the er promise in bar, before sending it
over to foo. Then foo receives simply an expression, which it can
then evaluate. Though I seem to have had to work a bit harder on that
part than I expected to. Perhaps there's an easier way? Or things
that can go seriously wrong with this way?
foo <- function(fr, expr) {
..obj <- list(.=fr)
..expr <- substitute(expr)
..txt <- parse( text=paste("substitute(",..expr,")") )
I think you want
..txt <- parse( text=paste("substitute(",deparse(..expr),")") )
here, but it's even better not to go through the deparse-parse cycle:
..txt <- bquote( substitute( .(..expr) ) )
The main thing that could go wrong is the evaluation of er might not be
right. Just because it is an argument to bar doesn't mean bar's frame
or parent.frame() is the right place to evaluate it.
To check for errors, I'd introduce like-named variables at lots of
levels, and then put them into the expression you were evaluating in
such a way that you can tell which one was found. For example, put
x <- "foo" into foo(), x <- "bar" into bar(), and x <- "global" into the
global environment. Then evaluate some expression that prints x and
make sure you see the right one.
Duncan Murdoch
..expr <- eval(..txt, ..obj, parent.frame())
..expr <- eval(..expr, parent.frame())
eval(..expr, ..obj)
}
bar <- function(parent, er, ...) {
.fr=parent
g <- substitute(er)
foo(.fr, g)
}
> foo(5,.)
[1] 5
> bar(5,.)
[1] 5
Duncan Murdoch
Haris Skiadas Department of Mathematics and Computer Science Hanover College
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
On 23/12/2007 9:15 AM, Duncan Murdoch wrote:
On 22/12/2007 5:45 PM, Charilaos Skiadas wrote:
On Dec 22, 2007, at 4:44 PM, Duncan Murdoch wrote:
5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace.
I think this part is wrong. A better description is: er is going to be evaluated in an environment where a is set to 5. The parent of that environment is the bar evaluation frame, where er is set to be a promise to evaluate a in the global environment.
7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a.
No, at this point an attempt is made to force the promise. Promises have their own associated environments, and that's where the evaluation takes place. In the case of the er object, the associated environment is the one where bar(a) was called, i.e. the global environment.
8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things.
Diagnosing things like this is hard. Promises are very difficult things to look at: as soon as you try to do anything with them they get evaluated, and there's no way in R code to display them without that. You can use substitute() to extract the expression part, but there's no way to extract the environment part. Maybe there should be, but it's tricky to get the semantics right. If the function environment() worked to extract the environment of a promise, then all sorts of code would fail where I really wanted to evaluate the arg before extracting the environment.
Thank you Duncan, for the very clear explanation.
Ok, so the substitute "breaks through" the promise of expr, returning
as a language object the promise of er, and there's no easy way to
break through that. I ended up with the following, somewhat uglier
than I wanted, code, which seems to do what I need in this case, and
hopefully will still work in the more general case I want it to. The
idea was to break through the er promise in bar, before sending it
over to foo. Then foo receives simply an expression, which it can
then evaluate. Though I seem to have had to work a bit harder on that
part than I expected to. Perhaps there's an easier way? Or things
that can go seriously wrong with this way?
foo <- function(fr, expr) {
..obj <- list(.=fr)
..expr <- substitute(expr)
..txt <- parse( text=paste("substitute(",..expr,")") )
I think you want
..txt <- parse( text=paste("substitute(",deparse(..expr),")") )
here, but it's even better not to go through the deparse-parse cycle:
..txt <- bquote( substitute( .(..expr) ) )
The main thing that could go wrong ...
Sorry, this wasn't written clearly: This was a response to your second question, not a continuation of the bquote() suggestion. Duncan Murdoch is the evaluation of er might not be
right. Just because it is an argument to bar doesn't mean bar's frame or parent.frame() is the right place to evaluate it. To check for errors, I'd introduce like-named variables at lots of levels, and then put them into the expression you were evaluating in such a way that you can tell which one was found. For example, put x <- "foo" into foo(), x <- "bar" into bar(), and x <- "global" into the global environment. Then evaluate some expression that prints x and make sure you see the right one. Duncan Murdoch
..expr <- eval(..txt, ..obj, parent.frame())
..expr <- eval(..expr, parent.frame())
eval(..expr, ..obj)
}
bar <- function(parent, er, ...) {
.fr=parent
g <- substitute(er)
foo(.fr, g)
}
> foo(5,.)
[1] 5
> bar(5,.)
[1] 5
Duncan Murdoch
Haris Skiadas Department of Mathematics and Computer Science Hanover College
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
______________________________________________ R-help at r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
On Dec 23, 2007, at 9:21 AM, Duncan Murdoch wrote:
On 23/12/2007 9:15 AM, Duncan Murdoch wrote:
On 22/12/2007 5:45 PM, Charilaos Skiadas wrote:
On Dec 22, 2007, at 4:44 PM, Duncan Murdoch wrote:
5) eval then creates the environment where this evaluation will take place. It does that by creating an environment containing the frame "a=5", and with enclosing environment the parent frame of foo, which is bar's environment. 6) So, as I understand it, the symbol "er" is going to now be evaluated in an environment where a is set to 5 and er is set to a, along with whatever is in the user's workspace.
I think this part is wrong. A better description is: er is going to be evaluated in an environment where a is set to 5. The parent of that environment is the bar evaluation frame, where er is set to be a promise to evaluate a in the global environment.
7) So the first step now is looking up a definition for er. Nothing is found in the current frame, so the evaluation proceeds to bar's environment, where the association "er=a" is found, so er is replaced by a.
No, at this point an attempt is made to force the promise. Promises have their own associated environments, and that's where the evaluation takes place. In the case of the er object, the associated environment is the one where bar(a) was called, i.e. the global environment.
8) Now, and perhaps this is where I misunderstand things, the lookup for a will take place. My thinking was that the lookup would start from the evaluation environment that eval created, and hence would locate the a=5 value. But this is clearly not what happens. Anyway, hope someone will correct me where I'm wrong, and explain to me what I am doing wrong, and ideally how to diagnose such things.
Diagnosing things like this is hard. Promises are very difficult things to look at: as soon as you try to do anything with them they get evaluated, and there's no way in R code to display them without that. You can use substitute() to extract the expression part, but there's no way to extract the environment part. Maybe there should be, but it's tricky to get the semantics right. If the function environment() worked to extract the environment of a promise, then all sorts of code would fail where I really wanted to evaluate the arg before extracting the environment.
Thank you Duncan, for the very clear explanation.
Ok, so the substitute "breaks through" the promise of expr,
returning as a language object the promise of er, and there's no
easy way to break through that. I ended up with the following,
somewhat uglier than I wanted, code, which seems to do what I
need in this case, and hopefully will still work in the more
general case I want it to. The idea was to break through the er
promise in bar, before sending it over to foo. Then foo receives
simply an expression, which it can then evaluate. Though I seem
to have had to work a bit harder on that part than I expected
to. Perhaps there's an easier way? Or things that can go
seriously wrong with this way?
foo <- function(fr, expr) {
..obj <- list(.=fr)
..expr <- substitute(expr)
..txt <- parse( text=paste("substitute(",..expr,")") )
I think you want
..txt <- parse( text=paste("substitute(",deparse(..expr),")") )
here, but it's even better not to go through the deparse-parse cycle:
..txt <- bquote( substitute( .(..expr) ) )
The main thing that could go wrong ...
Sorry, this wasn't written clearly: This was a response to your second question, not a continuation of the bquote() suggestion.
It was clear enough ;). I need to learn to use bquote more often .... Thanks, Haris Skiadas Department of Mathematics and Computer Science Hanover College
Duncan Murdoch is the evaluation of er might not be
right. Just because it is an argument to bar doesn't mean bar's frame or parent.frame() is the right place to evaluate it. To check for errors, I'd introduce like-named variables at lots of levels, and then put them into the expression you were evaluating in such a way that you can tell which one was found. For example, put x <- "foo" into foo(), x <- "bar" into bar(), and x <- "global" into the global environment. Then evaluate some expression that prints x and make sure you see the right one. Duncan Murdoch
..expr <- eval(..txt, ..obj, parent.frame())
..expr <- eval(..expr, parent.frame())
eval(..expr, ..obj)
}
bar <- function(parent, er, ...) {
.fr=parent
g <- substitute(er)
foo(.fr, g)
}
> foo(5,.)
[1] 5
> bar(5,.)
[1] 5