[R] Environmental oddity.

Duncan Murdoch murdoch@dunc@n @end|ng |rom gm@||@com
Sun Nov 7 18:20:16 CET 2021


Here's how to construct a similar deparsing error:

# e1 and e2 are obviously different expressions
e1 <- quote(5 * if (TRUE) 2 else 3/4)
e2 <- quote(5 * (if (TRUE) 2 else 3)/4)
# and they evaluate differently
eval(e1)
#> [1] 10
eval(e2)
#> [1] 2.5

# We can make an equivalent version of e2 by messing around in it
e3 <- e2
as.list(e3[[c(2,3)]])
#> [[1]]
#> `(`
#>
#> [[2]]
#> if (TRUE) 2 else 3
e3[[c(2,3)]] <- e3[[c(2,3,2)]]

# Now e3 looks like e1
e1
#> 5 * if (TRUE) 2 else 3/4
e3
#> 5 * if (TRUE) 2 else 3/4

# But it doesn't evaluate that way
eval(e1)
#> [1] 10
eval(e3)
#> [1] 2.5

Duncan Murdoch

On 07/11/2021 6:27 a.m., Duncan Murdoch wrote:
> On 06/11/2021 11:32 p.m., Deepayan Sarkar wrote:
>> On Sun, Nov 7, 2021 at 6:05 AM Rolf Turner <r.turner using auckland.ac.nz> wrote:
>>>
>>>
>>> I have two functions which appear to differ only in their environments.
>>> They look like:
>>>
>>>> d1
>>>> function (x, mean = 0, sd = 1, log = FALSE)
>>>> (((x - mean)/sd)^2 - 1) * if (log) 1 else dnorm(x, mean, sd)/sd
>>>> <environment: namespace:stats>
>>>
>>> and
>>>
>>>> d2
>>>> function (x, mean = 0, sd = 1, log = FALSE)
>>>> (((x - mean)/sd)^2 - 1) * if (log) 1 else dnorm(x, mean, sd)/sd
>>>
>>> Typing "environment(d1)" gives
>>>
>>>> <environment: namespace:stats>
>>>
>>> and typing "environment(d2)" gives
>>>
>>>> <environment: R_GlobalEnv>
>>>
>>> The d2() function however gives an incorrect result:
>>>
>>>> d1(1,0,3,TRUE)
>>>> [1] -0.2962963
>>>> d2(1,0,3,TRUE)
>>>> [1] -0.8888889
>>
>> It can't be as simple as that. I get the same result (as your d2) with
>> the following:
>>
>> d <- function (x, mean = 0, sd = 1, log = FALSE) {
>>       (((x - mean)/sd)^2 - 1) * if (log) 1 else dnorm(x, mean, sd) / sd
>> }
>> d(1, 0, 3, TRUE)
>> environment(d)
>> environment(d) <- as.environment("package:stats")
>> d(1, 0, 3, TRUE)
>>
>>> In d2() the result of the if() statement does not get divided
>>> by the final "sd" whereas in d1() it does (which is the desired/correct
>>> result).
>>>
>>> Of course the code is ridiculously kludgy (it was produced by "symbolic
>>> differentiation").  That's not the point.  I'm just curious (idly?) as
>>> to *why* the association of the namespace:stats environment with d1()
>>> causes it to "do the right thing".
>>
>> This sounds like a difference in precedence. The expression
>>
>> if (log) 1 else dnorm(x, mean, sd) / sd
>>
>> is apparently being interpreted differently as
>>
>> d1: (if (log) 1 else dnorm(x, mean, sd)) / sd
>> d2: if (log) 1 else (dnorm(x, mean, sd)) / sd)
>>
>> It's unclear how environments could affect this, so it would be very
>> helpful to have a reproducible example.
>>
> 
> Rolf said these were automatically produced functions.  Those don't
> always deparse properly, because manipulating expressions can produce
> things that can never be produced by the parser.  I'm not sure this
> happened in this case.  You'd need to examine the parse trees of d1 and
> d2 to see.
> 
> There's also a possibility that the srcref attached to them is lying,
> and we're not seeing the deparsed versions of the functions.  Printing
> removeSource(d1) and removeSource(d2) should reveal that.
> 
> Duncan Murdoch
>



More information about the R-help mailing list