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.

Reply via email to