I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
eval.w.with(a/2, dat) # Error ... 'a' not found
Thanks, Spencer Graves
with vs. attach
16 messages · Peter Dalgaard, Spencer Graves, David Winsemius +3 more
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
David. > > eval.w.with(a/2, dat) # Error ... 'a' not found > > > Thanks, Spencer Graves > > [[alternative HTML version deleted]] > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > 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. David Winsemius Alameda, CA, USA
Hi, David: That works. Thanks very much. Spencer Graves
On 5/5/2016 7:43 PM, David Winsemius wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
... and it's exactly with.default's code ! Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Thu, May 5, 2016 at 7:38 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
Hi, David: That works. Thanks very much. Spencer Graves On 5/5/2016 7:43 PM, David Winsemius wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 5/5/2016 11:17 PM, Bert Gunter wrote:
... and it's exactly with.default's code !
Thanks for pointing that out. Unfortunately, it didn't work inside another function. However, if I had looked at it, I might have been able to thought to try it. Spencer
Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Thu, May 5, 2016 at 7:38 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
Hi, David: That works. Thanks very much. Spencer Graves On 5/5/2016 7:43 PM, David Winsemius wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object). Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps: Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function. Apart from upsetting computer science purists, there could be hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic. So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0 Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found Thanks, Spencer Graves [[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
Peter Dalgaard, Professor, Center for Statistics, Copenhagen Business School Solbjerg Plads 3, 2000 Frederiksberg, Denmark Phone: (+45)38153501 Office: A 4.23 Email: pd.mes at cbs.dk Priv: PDalgd at gmail.com
On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object). Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps: Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function. Apart from upsetting computer science purists, there could be hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic. So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they don't
automatically accept what I naively thought should work and require more
knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
> eval.w.sub(a/2, dat)
[1] 0.5 1.0
This produces what's desired in a way that seems simpler to me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
> eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
> eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachOops(b/2, dat) : object 'b' not found
> search()
[1] ".GlobalEnv" "Dat" "package:graphics"
[4] "package:grDevices" "package:utils" "package:datasets"
[7] "package:methods" "Autoloads" "package:base"
> objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a" exists
in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached
"package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but not the
likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
> eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
> search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found Thanks, Spencer Graves [[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 May 6, 2016, at 5:47 AM, Spencer Graves <spencer.graves at effectivedefense.org> wrote: On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object). Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps: Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function. Apart from upsetting computer science purists, there could be hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic. So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
>
>
>
> This produces what's desired in a way that seems simpler to me.
>
>
> By the way, I really appreciate Peter's insightful comments:
>
>
> eval.w.attachOops <- function(x, Dat){
> attach(Dat)
> X <- x
> detach()
> X
> }
> > eval.w.attachOops(a/2, dat)
> The following object is masked _by_ .GlobalEnv:
>
> a
>
> [1] 1.570796
> > eval.w.attachOops(b/2, dat)
> The following object is masked _by_ .GlobalEnv:
>
> a
>
> Error in eval.w.attachOops(b/2, dat) : object 'b' not found
> > search()
> [1] ".GlobalEnv" "Dat" "package:graphics"
> [4] "package:grDevices" "package:utils" "package:datasets"
> [7] "package:methods" "Autoloads" "package:base"
> > objects(2)
> [1] "a"
>
> *** NOTES:
>
>
> 1. This gives a likely wrong answer with a warning if "a" exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
>
>
>
> 2. A stray "detach()" [not shown here] detached "package:stats". oops.
>
>
> *** Using "on.exit" fixes the problem with failure to detach but not the likely wrong answer:
>
>
> detach()
> search()
> eval.w.attachStillWrong <- function(x, dat){
> attach(dat)
> on.exit(detach(dat))
> X <- x
> X
> }
> The following object is masked _by_ .GlobalEnv:
>
> a
>
> [1] 1.570796
> > eval.w.attachStillWrong(b/2, dat)
> The following object is masked _by_ .GlobalEnv:
>
> a
>
> Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
> > search()
> [1] ".GlobalEnv" "package:grDevices" "package:utils"
> [4] "package:datasets" "package:methods" "Autoloads"
> [7] "package:base"
>
>
> Thanks again to Peter and David. Spencer
>
>> Peter D.
>>
>>
>>
>>> --
>>> David.
>>>
>>>
>>>> eval.w.with(a/2, dat) # Error ... 'a' not found
>>>>
>>>>
>>>> Thanks, Spencer Graves
>>>>
>>>> [[alternative HTML version deleted]]
>>>>
>>>> ______________________________________________
>>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>>> 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.
>>> David Winsemius
>>> Alameda, CA, USA
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>> 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.
David Winsemius
Alameda, CA, USA
You may want to read http://rpubs.com/hadley/157957, which captures my latest thinking (and tooling) around this problem. Feedback is much appreciated. Hadley
On Fri, May 6, 2016 at 2:14 PM, David Winsemius <dwinsemius at comcast.net> wrote:
On May 6, 2016, at 5:47 AM, Spencer Graves <spencer.graves at effectivedefense.org> wrote: On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object). Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps: Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function. Apart from upsetting computer science purists, there could be hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic. So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
--
This produces what's desired in a way that seems simpler to me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv: a [1] 1.570796
eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv: a Error in eval.w.attachOops(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "Dat" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base"
objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a" exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached "package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but not the likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv: a Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found Thanks, Spencer Graves [[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
2 days later
Hi, Hadley et al.:
Hadley's link requires his development version of "lazyeval",
which can be obtained as follows:
library(devtools)
install_github("hadley/lazyeval")
Hadley's link describes real problems with elegant solutions.
However, David's solution solved my immediate problem, and it's
not immediately obvious to me how his "expr_text" function (or other
functions in "lazyevel") to produce a better solution.
Thanks again to David, Peter and Hadley for their replies.
Spencer Graves
On 5/6/2016 5:08 PM, Hadley Wickham wrote:
You may want to read http://rpubs.com/hadley/157957, which captures my latest thinking (and tooling) around this problem. Feedback is much appreciated. Hadley On Fri, May 6, 2016 at 2:14 PM, David Winsemius <dwinsemius at comcast.net> wrote:
On May 6, 2016, at 5:47 AM, Spencer Graves <spencer.graves at effectivedefense.org> wrote: On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius <dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object). Once you figure out _how_ your eval.w.attach works (sort of), you'll get the creeps: Lazy evaluation causes the argument x to be evaluated after the attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function. Apart from upsetting computer science purists, there could be hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic. So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
--
This produces what's desired in a way that seems simpler to me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachOops(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "Dat" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base"
objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a" exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached "package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but not the likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found
Thanks, Spencer Graves
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
David Winsemius Alameda, CA, USA
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
The lazyeval package addresses the problem of how to delay evaluation even when the function you want to do the evaluation in is buried two or more function calls below where the original call was made. If you are not building nested function calls with delayed evaluation then you probably don't need that package.
Sent from my phone. Please excuse my brevity.
On May 8, 2016 3:30:16 PM PDT, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
>Hi, Hadley et al.:
>
>
> Hadley's link requires his development version of "lazyeval",
>which can be obtained as follows:
>
>
>library(devtools)
>install_github("hadley/lazyeval")
>
>
> Hadley's link describes real problems with elegant solutions.
>
>
> However, David's solution solved my immediate problem, and it's
>not immediately obvious to me how his "expr_text" function (or other
>functions in "lazyevel") to produce a better solution.
>
>
> Thanks again to David, Peter and Hadley for their replies.
>
>
> Spencer Graves
>
>
>On 5/6/2016 5:08 PM, Hadley Wickham wrote:
>> You may want to read http://rpubs.com/hadley/157957, which captures
>my
>> latest thinking (and tooling) around this problem. Feedback is much
>> appreciated.
>>
>> Hadley
>>
>> On Fri, May 6, 2016 at 2:14 PM, David Winsemius
><dwinsemius at comcast.net> wrote:
>>>> On May 6, 2016, at 5:47 AM, Spencer Graves
><spencer.graves at effectivedefense.org> wrote:
>>>>
>>>>
>>>>
>>>> On 5/6/2016 6:46 AM, peter dalgaard wrote:
>>>>> On 06 May 2016, at 02:43 , David Winsemius
><dwinsemius at comcast.net> wrote:
>>>>>
>>>>>>> On May 5, 2016, at 5:12 PM, Spencer Graves
><spencer.graves at effectivedefense.org> wrote:
>>>>>>>
>>>>>>> I want a function to evaluate one argument
>>>>>>> in the environment of a data.frame supplied
>>>>>>> as another argument. "attach" works for
>>>>>>> this, but "with" does not. Is there a way
>>>>>>> to make "with" work? I'd rather not attach
>>>>>>> the data.frame.
>>>>>>>
>>>>>>>
>>>>>>> With the following two functions "eval.w.attach"
>>>>>>> works but "eval.w.with" fails:
>>>>>>>
>>>>>>>
>>>>>>> dat <- data.frame(a=1:2)
>>>>>>> eval.w.attach <- function(x, dat){
>>>>>>> attach(dat)
>>>>>>> X <- x
>>>>>>> detach()
>>>>>>> X
>>>>>>> }
>>>>>>>
>>>>>>> eval.w.with <- function(x, dat){
>>>>>>> with(dat, x)
>>>>>>> }
>>>>>>>
>>>>>>> eval.w.attach(a/2, dat) # returns c(.5, 1)
>>>>>> How about using eval( substitute( ...))?
>>>>>>
>>>>>> eval.w.sub <- function(expr, datt){
>>>>>> eval( substitute(expr), env=datt)
>>>>>> }
>>>>>> eval.w.sub(a/2, dat)
>>>>>> #[1] 0.5 1.0
>>>>>>
>>>>>>
>>>>> Actually, I think a better overall strategy is to say that if you
>want to pass an expression to a function, then pass an expression
>object (or a call object or maybe a formula object).
>>>>>
>>>>> Once you figure out _how_ your eval.w.attach works (sort of),
>you'll get the creeps:
>>>>>
>>>>> Lazy evaluation causes the argument x to be evaluated after the
>attach(), hence the evaluation environment of an actual argument is
>being temporarily modified from inside a function.
>>>>>
>>>>> Apart from upsetting computer science purists, there could be
>hidden problems: One major issue is that values in "dat" could be
>masked by values in the global environment, another issue is that an
>error in evaluating the expression will leave dat attached. So at a
>minimum, you need to recode using on.exit() magic.
>>>>>
>>>>> So my preferences go along these lines:
>>>>>
>>>>>> dat <- data.frame(a=1:2)
>>>>>> eval.expression <- function(e, dat) eval(e, dat)
>>>>>> eval.expression(quote(a/2), dat)
>>>>> [1] 0.5 1.0
>>>>>> eval.expression(expression(a/2), dat)
>>>>> [1] 0.5 1.0
>>>>>
>>>>>> eval.formula <- function(f, dat) eval(f[[2]], dat)
>>>>>> eval.formula(~a/2, dat)
>>>>> [1] 0.5 1.0
>>>> Hi, Peter:
>>>>
>>>>
>>>> I don't like eval.expression or eval.formula, because they
>don't automatically accept what I naively thought should work and
>require more knowledge of the user. What about David's eval.w.sub:
>>>>
>>>>
>>>> a <- pi
>>>> dat <- data.frame(a=1:2)
>>>> eval.w.sub <- function(a, Dat){
>>>> eval( substitute(a), env=Dat)
>>>> }
>>>>> eval.w.sub(a/2, dat)
>>>> [1] 0.5 1.0
>>> I liked eval.expression and tested it with a bquote(...) argument to
>see if that would succeed. It did, but it didn't return what you wanted
>for `a/2`, so I tried seeing if a "double eval wuold deliver both yours
>and my desired results:
>>>
>>> eval.w.sub <- function(a, Dat){
>>> eval( eval(substitute(a),Dat), env=Dat)
>>> }
>>> x=2
>>> eval.w.sub( a/2, dat)
>>> [1] 0.5 1.0
>>> eval.w.sub( bquote(2*a*.(x) ), dat)
>>> [1] 4 8
>>>
>>> We are here retracing the path the Hadley took in some of his
>ggplot2 design decsions. Unfortunately for me those NSE rules often
>left me confused about what should and shouldn't be 'quoted' in the
>as-character sense and what should be quote()-ed or "unquoted" in the
>bquote() sense.
>>> --
>>>
>>>>
>>>>
>>>> This produces what's desired in a way that seems simpler to
>me.
>>>>
>>>>
>>>> By the way, I really appreciate Peter's insightful comments:
>>>>
>>>>
>>>> eval.w.attachOops <- function(x, Dat){
>>>> attach(Dat)
>>>> X <- x
>>>> detach()
>>>> X
>>>> }
>>>>> eval.w.attachOops(a/2, dat)
>>>> The following object is masked _by_ .GlobalEnv:
>>>>
>>>> a
>>>>
>>>> [1] 1.570796
>>>>> eval.w.attachOops(b/2, dat)
>>>> The following object is masked _by_ .GlobalEnv:
>>>>
>>>> a
>>>>
>>>> Error in eval.w.attachOops(b/2, dat) : object 'b' not found
>>>>> search()
>>>> [1] ".GlobalEnv" "Dat" "package:graphics"
>>>> [4] "package:grDevices" "package:utils" "package:datasets"
>>>> [7] "package:methods" "Autoloads" "package:base"
>>>>> objects(2)
>>>> [1] "a"
>>>>
>>>> *** NOTES:
>>>>
>>>>
>>>> 1. This gives a likely wrong answer with a warning if "a"
>exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
>>>>
>>>>
>>>>
>>>> 2. A stray "detach()" [not shown here] detached
>"package:stats". oops.
>>>>
>>>>
>>>> *** Using "on.exit" fixes the problem with failure to detach but
>not the likely wrong answer:
>>>>
>>>>
>>>> detach()
>>>> search()
>>>> eval.w.attachStillWrong <- function(x, dat){
>>>> attach(dat)
>>>> on.exit(detach(dat))
>>>> X <- x
>>>> X
>>>> }
>>>> The following object is masked _by_ .GlobalEnv:
>>>>
>>>> a
>>>>
>>>> [1] 1.570796
>>>>> eval.w.attachStillWrong(b/2, dat)
>>>> The following object is masked _by_ .GlobalEnv:
>>>>
>>>> a
>>>>
>>>> Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
>>>>> search()
>>>> [1] ".GlobalEnv" "package:grDevices" "package:utils"
>>>> [4] "package:datasets" "package:methods" "Autoloads"
>>>> [7] "package:base"
>>>>
>>>>
>>>> Thanks again to Peter and David. Spencer
>>>>
>>>>> Peter D.
>>>>>
>>>>>
>>>>>
>>>>>> --
>>>>>> David.
>>>>>>
>>>>>>
>>>>>>> eval.w.with(a/2, dat) # Error ... 'a' not found
>>>>>>>
>>>>>>>
>>>>>>> Thanks, Spencer Graves
>>>>>>>
>>>>>>> [[alternative HTML version deleted]]
>>>>>>>
>>>>>>> ______________________________________________
>>>>>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
>see
>>>>>>> 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.
>>>>>> David Winsemius
>>>>>> Alameda, CA, USA
>>>>>>
>>>>>> ______________________________________________
>>>>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>>>>> 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.
>>> David Winsemius
>>> Alameda, CA, USA
>>>
>>> ______________________________________________
>>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>> 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 -- To UNSUBSCRIBE and more, see
>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.
[[alternative HTML version deleted]]
Jeff: That's easy to do already with substitute(), since you can pass around an unevaluated expression (a parse tree) however you like. As I read it, (admittedly quickly) what it's main feature is that it allows you more control over the environment in which the expression is finally evaluated -- as well as permitting nested expression evaluation fairly easily. But maybe we're saying the same thing ... IMHO I think Hadley has gone overboard here, worrying about rarely important issues, as you seem to be intimating also. Feel free to set me straight... or ignore. Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
On Sun, May 8, 2016 at 4:02 PM, Jeff Newmiller <jdnewmil at dcn.davis.ca.us> wrote:
The lazyeval package addresses the problem of how to delay evaluation even when the function you want to do the evaluation in is buried two or more function calls below where the original call was made. If you are not building nested function calls with delayed evaluation then you probably don't need that package. -- Sent from my phone. Please excuse my brevity. On May 8, 2016 3:30:16 PM PDT, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
Hi, Hadley et al.:
Hadley's link requires his development version of "lazyeval",
which can be obtained as follows:
library(devtools)
install_github("hadley/lazyeval")
Hadley's link describes real problems with elegant solutions.
However, David's solution solved my immediate problem, and it's
not immediately obvious to me how his "expr_text" function (or other
functions in "lazyevel") to produce a better solution.
Thanks again to David, Peter and Hadley for their replies.
Spencer Graves
On 5/6/2016 5:08 PM, Hadley Wickham wrote:
You may want to read http://rpubs.com/hadley/157957, which captures
my
latest thinking (and tooling) around this problem. Feedback is much appreciated. Hadley On Fri, May 6, 2016 at 2:14 PM, David Winsemius
<dwinsemius at comcast.net> wrote:
On May 6, 2016, at 5:47 AM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius
<dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you
want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object).
Once you figure out _how_ your eval.w.attach works (sort of),
you'll get the creeps:
Lazy evaluation causes the argument x to be evaluated after the
attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function.
Apart from upsetting computer science purists, there could be
hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic.
So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they
don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to
see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his
ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
--
This produces what's desired in a way that seems simpler to
me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachOops(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "Dat" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base"
objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a"
exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached
"package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but
not the likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found
Thanks, Spencer Graves
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
see
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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 -- To UNSUBSCRIBE and more, see 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.
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
... To be clear, Hadley or anyone else should also feel free to set me straight, preferably publicly, but privately if you prefer. Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
On Sun, May 8, 2016 at 5:28 PM, Bert Gunter <bgunter.4567 at gmail.com> wrote:
Jeff: That's easy to do already with substitute(), since you can pass around an unevaluated expression (a parse tree) however you like. As I read it, (admittedly quickly) what it's main feature is that it allows you more control over the environment in which the expression is finally evaluated -- as well as permitting nested expression evaluation fairly easily. But maybe we're saying the same thing ... IMHO I think Hadley has gone overboard here, worrying about rarely important issues, as you seem to be intimating also. Feel free to set me straight... or ignore. Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Sun, May 8, 2016 at 4:02 PM, Jeff Newmiller <jdnewmil at dcn.davis.ca.us> wrote:
The lazyeval package addresses the problem of how to delay evaluation even when the function you want to do the evaluation in is buried two or more function calls below where the original call was made. If you are not building nested function calls with delayed evaluation then you probably don't need that package. -- Sent from my phone. Please excuse my brevity. On May 8, 2016 3:30:16 PM PDT, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
Hi, Hadley et al.:
Hadley's link requires his development version of "lazyeval",
which can be obtained as follows:
library(devtools)
install_github("hadley/lazyeval")
Hadley's link describes real problems with elegant solutions.
However, David's solution solved my immediate problem, and it's
not immediately obvious to me how his "expr_text" function (or other
functions in "lazyevel") to produce a better solution.
Thanks again to David, Peter and Hadley for their replies.
Spencer Graves
On 5/6/2016 5:08 PM, Hadley Wickham wrote:
You may want to read http://rpubs.com/hadley/157957, which captures
my
latest thinking (and tooling) around this problem. Feedback is much appreciated. Hadley On Fri, May 6, 2016 at 2:14 PM, David Winsemius
<dwinsemius at comcast.net> wrote:
On May 6, 2016, at 5:47 AM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius
<dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you
want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object).
Once you figure out _how_ your eval.w.attach works (sort of),
you'll get the creeps:
Lazy evaluation causes the argument x to be evaluated after the
attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function.
Apart from upsetting computer science purists, there could be
hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic.
So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they
don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to
see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his
ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
--
This produces what's desired in a way that seems simpler to
me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachOops(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "Dat" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base"
objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a"
exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached
"package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but
not the likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv:
a
Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found
Thanks, Spencer Graves
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
see
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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 -- To UNSUBSCRIBE and more, see 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.
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 09 May 2016, at 02:46 , Bert Gunter <bgunter.4567 at gmail.com> wrote:
... To be clear, Hadley or anyone else should also feel free to set me straight, preferably publicly, but privately if you prefer.
Not really to "set anyone straight", but there are some subtleties with mode call objects versus expression objects and formulas to be aware of. E.g.,
a <- 2
do.call("print", list(a*pi))
[1] 6.283185
do.call("print", list(quote(a*pi)))
[1] 6.283185
do.call("print", list(expression(a*pi)))
expression(a * pi)
do.call("print", list(~a*pi))
~a * pi Thing is, if you insert a call object into a parse tree, nothing is there to preserve its nature as an unevaluated expression. Similarly, in
call("print", quote(a*pi))
print(a * pi) the result is identical to quote(print(a * pi)), so when evaluated, quoting is not seen by print(). As far as I understand, this is also the reason that for math in ggplot, you may need as.expression(bquote(....)). In general, I think that a number of things in R had been more cleanly implemented using formulas/expression objects than using substitution and lazy evaluation, notably subset and offset arguments in lm/glm. It would have been so much cleaner to have lm(math ~ age, data = foo, subset = ~ sex=="1") than the current situation where lm internally chops its own head off and substitutes with model.frame, then evaluates the call to model.frame() which in turn does eval(substitute(subset), data, env). Of course, at the time, ~ was intended specifically for Wilkinson Rogers type formulas; "abusing" it for other kinds of expressions is something of an afterthought. -pd
Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Sun, May 8, 2016 at 5:28 PM, Bert Gunter <bgunter.4567 at gmail.com> wrote:
Jeff: That's easy to do already with substitute(), since you can pass around an unevaluated expression (a parse tree) however you like. As I read it, (admittedly quickly) what it's main feature is that it allows you more control over the environment in which the expression is finally evaluated -- as well as permitting nested expression evaluation fairly easily. But maybe we're saying the same thing ... IMHO I think Hadley has gone overboard here, worrying about rarely important issues, as you seem to be intimating also. Feel free to set me straight... or ignore. Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Sun, May 8, 2016 at 4:02 PM, Jeff Newmiller <jdnewmil at dcn.davis.ca.us> wrote:
The lazyeval package addresses the problem of how to delay evaluation even when the function you want to do the evaluation in is buried two or more function calls below where the original call was made. If you are not building nested function calls with delayed evaluation then you probably don't need that package. -- Sent from my phone. Please excuse my brevity. On May 8, 2016 3:30:16 PM PDT, Spencer Graves <spencer.graves at effectivedefense.org> wrote:
Hi, Hadley et al.:
Hadley's link requires his development version of "lazyeval",
which can be obtained as follows:
library(devtools)
install_github("hadley/lazyeval")
Hadley's link describes real problems with elegant solutions.
However, David's solution solved my immediate problem, and it's
not immediately obvious to me how his "expr_text" function (or other
functions in "lazyevel") to produce a better solution.
Thanks again to David, Peter and Hadley for their replies.
Spencer Graves
On 5/6/2016 5:08 PM, Hadley Wickham wrote:
You may want to read http://rpubs.com/hadley/157957, which captures
my
latest thinking (and tooling) around this problem. Feedback is much appreciated. Hadley On Fri, May 6, 2016 at 2:14 PM, David Winsemius
<dwinsemius at comcast.net> wrote:
On May 6, 2016, at 5:47 AM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
On 5/6/2016 6:46 AM, peter dalgaard wrote:
On 06 May 2016, at 02:43 , David Winsemius
<dwinsemius at comcast.net> wrote:
On May 5, 2016, at 5:12 PM, Spencer Graves
<spencer.graves at effectivedefense.org> wrote:
I want a function to evaluate one argument
in the environment of a data.frame supplied
as another argument. "attach" works for
this, but "with" does not. Is there a way
to make "with" work? I'd rather not attach
the data.frame.
With the following two functions "eval.w.attach"
works but "eval.w.with" fails:
dat <- data.frame(a=1:2)
eval.w.attach <- function(x, dat){
attach(dat)
X <- x
detach()
X
}
eval.w.with <- function(x, dat){
with(dat, x)
}
eval.w.attach(a/2, dat) # returns c(.5, 1)
How about using eval( substitute( ...))?
eval.w.sub <- function(expr, datt){
eval( substitute(expr), env=datt)
}
eval.w.sub(a/2, dat)
#[1] 0.5 1.0
Actually, I think a better overall strategy is to say that if you
want to pass an expression to a function, then pass an expression object (or a call object or maybe a formula object).
Once you figure out _how_ your eval.w.attach works (sort of),
you'll get the creeps:
Lazy evaluation causes the argument x to be evaluated after the
attach(), hence the evaluation environment of an actual argument is being temporarily modified from inside a function.
Apart from upsetting computer science purists, there could be
hidden problems: One major issue is that values in "dat" could be masked by values in the global environment, another issue is that an error in evaluating the expression will leave dat attached. So at a minimum, you need to recode using on.exit() magic.
So my preferences go along these lines:
dat <- data.frame(a=1:2) eval.expression <- function(e, dat) eval(e, dat) eval.expression(quote(a/2), dat)
[1] 0.5 1.0
eval.expression(expression(a/2), dat)
[1] 0.5 1.0
eval.formula <- function(f, dat) eval(f[[2]], dat) eval.formula(~a/2, dat)
[1] 0.5 1.0
Hi, Peter:
I don't like eval.expression or eval.formula, because they
don't automatically accept what I naively thought should work and require more knowledge of the user. What about David's eval.w.sub:
a <- pi
dat <- data.frame(a=1:2)
eval.w.sub <- function(a, Dat){
eval( substitute(a), env=Dat)
}
eval.w.sub(a/2, dat)
[1] 0.5 1.0
I liked eval.expression and tested it with a bquote(...) argument to
see if that would succeed. It did, but it didn't return what you wanted for `a/2`, so I tried seeing if a "double eval wuold deliver both yours and my desired results:
eval.w.sub <- function(a, Dat){
eval( eval(substitute(a),Dat), env=Dat)
}
x=2
eval.w.sub( a/2, dat)
[1] 0.5 1.0
eval.w.sub( bquote(2*a*.(x) ), dat)
[1] 4 8
We are here retracing the path the Hadley took in some of his
ggplot2 design decsions. Unfortunately for me those NSE rules often left me confused about what should and shouldn't be 'quoted' in the as-character sense and what should be quote()-ed or "unquoted" in the bquote() sense.
--
This produces what's desired in a way that seems simpler to
me.
By the way, I really appreciate Peter's insightful comments:
eval.w.attachOops <- function(x, Dat){
attach(Dat)
X <- x
detach()
X
}
eval.w.attachOops(a/2, dat)
The following object is masked _by_ .GlobalEnv: a [1] 1.570796
eval.w.attachOops(b/2, dat)
The following object is masked _by_ .GlobalEnv: a Error in eval.w.attachOops(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "Dat" "package:graphics" [4] "package:grDevices" "package:utils" "package:datasets" [7] "package:methods" "Autoloads" "package:base"
objects(2)
[1] "a"
*** NOTES:
1. This gives a likely wrong answer with a warning if "a"
exists in .GlobalEnv, and leaves "Dat" (NOT "dat") attached upon exit.
2. A stray "detach()" [not shown here] detached
"package:stats". oops.
*** Using "on.exit" fixes the problem with failure to detach but
not the likely wrong answer:
detach()
search()
eval.w.attachStillWrong <- function(x, dat){
attach(dat)
on.exit(detach(dat))
X <- x
X
}
The following object is masked _by_ .GlobalEnv:
a
[1] 1.570796
eval.w.attachStillWrong(b/2, dat)
The following object is masked _by_ .GlobalEnv: a Error in eval.w.attachStillWrong(b/2, dat) : object 'b' not found
search()
[1] ".GlobalEnv" "package:grDevices" "package:utils"
[4] "package:datasets" "package:methods" "Autoloads"
[7] "package:base"
Thanks again to Peter and David. Spencer
Peter D.
-- David.
eval.w.with(a/2, dat) # Error ... 'a' not found Thanks, Spencer Graves [[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more,
see
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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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. David Winsemius Alameda, CA, USA ______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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 -- To UNSUBSCRIBE and more, see 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.
[[alternative HTML version deleted]]
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see 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.
Peter Dalgaard, Professor, Center for Statistics, Copenhagen Business School Solbjerg Plads 3, 2000 Frederiksberg, Denmark Phone: (+45)38153501 Office: A 4.23 Email: pd.mes at cbs.dk Priv: PDalgd at gmail.com
On Sun, May 8, 2016 at 7:28 PM, Bert Gunter <bgunter.4567 at gmail.com> wrote:
Jeff: That's easy to do already with substitute(), since you can pass around an unevaluated expression (a parse tree) however you like. As I read it, (admittedly quickly) what it's main feature is that it allows you more control over the environment in which the expression is finally evaluated -- as well as permitting nested expression evaluation fairly easily. But maybe we're saying the same thing ... IMHO I think Hadley has gone overboard here, worrying about rarely important issues, as you seem to be intimating also.
These are absolutely critical issues that crop up as soon as other people want to write functions that use your functions that use NSE. Hadley
On Mon, May 9, 2016 at 7:12 AM, peter dalgaard <pdalgd at gmail.com> wrote:
On 09 May 2016, at 02:46 , Bert Gunter <bgunter.4567 at gmail.com> wrote:
... To be clear, Hadley or anyone else should also feel free to set me straight, preferably publicly, but privately if you prefer.
Not really to "set anyone straight", but there are some subtleties with mode call objects versus expression objects and formulas to be aware of. E.g.,
a <- 2
do.call("print", list(a*pi))
[1] 6.283185
do.call("print", list(quote(a*pi)))
[1] 6.283185
do.call("print", list(expression(a*pi)))
expression(a * pi)
do.call("print", list(~a*pi))
~a * pi Thing is, if you insert a call object into a parse tree, nothing is there to preserve its nature as an unevaluated expression. Similarly, in
call("print", quote(a*pi))
print(a * pi) the result is identical to quote(print(a * pi)), so when evaluated, quoting is not seen by print(). As far as I understand, this is also the reason that for math in ggplot, you may need as.expression(bquote(....)). In general, I think that a number of things in R had been more cleanly implemented using formulas/expression objects than using substitution and lazy evaluation, notably subset and offset arguments in lm/glm. It would have been so much cleaner to have lm(math ~ age, data = foo, subset = ~ sex=="1") than the current situation where lm internally chops its own head off and substitutes with model.frame, then evaluates the call to model.frame() which in turn does eval(substitute(subset), data, env). Of course, at the time, ~ was intended specifically for Wilkinson Rogers type formulas; "abusing" it for other kinds of expressions is something of an afterthought.
Yeah, to my mind, the cool thing about formulas is that they provide a concise way to capture an environment and an expression, and then Wilkinson Rogers are just a special case. It's obvious impossible to go back and change how lm() etc works now, but I'm reasonably confident that lazyeval provides a strong foundation going forward. The quasiquotation stuff is particularly important - and unquote-splice makes it possible to do things that are impossible with bquote(). (Of course, unquote-splice could be added to bquote(), but I think you'll still run into issues with environments) Hadley