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 <dwinsem...@comcast.net> wrote: > >> On May 6, 2016, at 5:47 AM, Spencer Graves >> <spencer.gra...@effectivedefense.org> wrote: >> >> >> >> On 5/6/2016 6:46 AM, peter dalgaard wrote: >>> On 06 May 2016, at 02:43 , David Winsemius <dwinsem...@comcast.net> wrote: >>> >>>>> On May 5, 2016, at 5:12 PM, Spencer Graves >>>>> <spencer.gra...@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@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@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@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. -- http://hadley.nz ______________________________________________ R-help@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.