[Rd] Curious behavior of $ and lapply

Kevin Ushey kevinushey at gmail.com
Tue Jun 24 08:28:04 CEST 2014


`lapply` basically takes its call and massages into calls of the following form:

    FUN(X[[1L]], ...)
    FUN(X[[2L]], ...)
    ... <up to length of X>

that get evaluated in the appropriate environment.

For `lapply(list(list(a=3,b=4)),"$","b")`, you can imagine that a
function `FUN` of the form:

    FUN <- function(x, ...) "$"(x, ...)

is being generated, and then evaluated as

    FUN(list(list(a=3, b=4))[[1L]], "b") ## returns NULL

and I can only guess that the non-standard evaluation of `$` is not
interpreting `...` as you expect.

Moral of the story -- lapply does non-standard evaluation, and does
not compose nicely with other functions performing non-standard
evaluation. This is discussed a bit in the Note: section of `?lapply`.
Copied from there (emphasis mine):

For historical reasons, the calls created by lapply are unevaluated,
and code has been written (e.g. bquote) that relies on this. This
means that the recorded call is always of the form FUN(X[[i]], ...),
with i replaced by the current (integer or double) index. This is not
normally a problem, but it can be if FUN uses sys.call or match.call
or if it __is a primitive function that makes use of the call__. This
means that it is often safer to call primitive functions with a
wrapper, so that e.g. lapply(ll, function(x) is.numeric(x)) is
required to ensure that method dispatch for is.numeric occurs
correctly.

Cheers,
Kevin


On Mon, Jun 23, 2014 at 3:04 PM, Stavros Macrakis (Σταῦρος Μακράκης)
<macrakis at alum.mit.edu> wrote:
> There seems to be a funny interaction between lapply and "$" -- also, "$"
> doesn't signal an error in some cases where "[[" does.
>
> The $ operator accepts a string second argument in functional form:
>
>> `$`(list(a=3,b=4),"b")
> [1] 4
>
> lapply(list(list(a=3,b=4)),function(x) `$`(x,"b"))
> [[1]]
> [1] 4
>
> ... but using an lapply "..." argument, this returns NULL:
>
>> lapply(list(list(a=3,b=4)),"$","b")
> [[1]]
> NULL
>
> Equally strangely, a symbol is an error in functional form:
>
>>  `$`(list(a=3,b=4),quote(`b`))
> Error in list(a = 3, b = 4)$quote(b) : invalid subscript type 'language'
>
> ... but not an error in lapply, where it returns NULL:
>
>> lapply(list(list(a=3,b=4)),`$`,quote(`b`))
> [[1]]
> NULL
>
> I wonder if lapply is failing to pass the second argument to $ correctly,
> since $ with various unreasonable second arguments returns NULL (shouldn't
> it given an error?):
>
> "$"(list(list(a=3,b=4)),) => NULL
> lapply(list(list(a=3,b=4)),`$`,function(i)i) => NULL
>
> Compare
>
> "[["(list(list(a=3,b=4)),) => <<error>>
>
> But with [[, lapply correctly gives an error:
>
> lapply(list(list(a=3,b=4)),`[[`,function(i)i) => <<error>>
>
>         [[alternative HTML version deleted]]
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel



More information about the R-devel mailing list