8

I was going through some examples in hadley's guide to functionals, and came across an unexpected problem.

Suppose I have a list of model objects,

x=1:3;y=3:1; bah <- list(lm(x~y),lm(y~x))

and want to extract something from each (as suggested in hadley's question about a list called "trials"). I was expecting one of these to work:

lapply(bah,`$`,i='call') # or...
lapply(bah,`$`,call)

However, these return nulls. It seems like I'm not misusing the $ function, as these things work:

`$`(bah[[1]],i='call')
`$`(bah[[1]],call)

Anyway, I'm just doing this as an exercise and am curious where my mistake is. I know I could use an anonymous function, but think there must be a way to use syntax similar to my initial non-solution. I've looked through the places $ is mentioned in ?Extract, but didn't see any obvious explanation.

I just realized that this works:

lapply(bah,`[[`,i='call')

and this

lapply(bah,function(x)`$`(x,call))

Maybe this just comes down to some lapply voodoo that demands anonymous functions where none should be needed? I feel like I've heard that somewhere on SO before.

Frank
  • 66,179
  • 8
  • 96
  • 180
  • 2
    No voodoo. The "$" function does not evaluate its arguments, whereas "[[" does. – IRTFM Aug 13 '13 at 18:15
  • 3
    @DWin - can you please expound, I don't understand what you mean by that – eddi Aug 13 '13 at 18:23
  • @Dwin Maybe this is just over my head, but I'm not clear on what evaluation means here. It seems to evaluate args okay when called directly, as in `\`$\`(bah[[1]],i='call')`...? (argh: escaping inline backticks is annoying) – Frank Aug 13 '13 at 18:23
  • 3
    You can do either `ll[[varname]]` or `ll[['varname']]` and they mean different things. The first looks up the value of `varname`. With `$` you only get the second option, since it will never "reach out" and evaluate what character value `varname` might have had in the enclosing environment. – IRTFM Aug 13 '13 at 18:35
  • @DWin wouldn't `lapply(bah, \`$\`, 'call')` work then? – eddi Aug 13 '13 at 18:39
  • Not sure why `lapply(bah, `$`, 'call')` fails. I was surprised that `\`$\`(bah[[1]],call)` worked. Was expecting the same error that I get with: `lapply(bah, "[[", call)` stemming from the fact that `call` is a language function. – IRTFM Aug 13 '13 at 18:56
  • the impression I'm getting is that the `lapply` results in calls like this: `\`$\`(bah[[1]], )`, but I don't understand why – eddi Aug 13 '13 at 19:00
  • 2
    @eddi: the "Note" in the Details seciton of `?lapply` looks on point for that question. – IRTFM Aug 13 '13 at 19:08
  • My apologies for some of these comments that I now see as tangential. Would be more than happy to delete them, but didn't want to leave the responses dangling if the authors wanted to leave them up. – IRTFM Aug 13 '13 at 19:14
  • 1
    @DWin Ah, okay. That answers the question, I think. $ is a primitive, so lapply misbehaves. Thanks – Frank Aug 13 '13 at 19:17

1 Answers1

5

This is documented in ?lapply, in the "Note" section (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[[0L]], ...), with 0L replaced by the current integer 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 in R 2.7.1 to ensure that method dispatch for is.numeric occurs correctly.

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • I'm still a bit confused - what call for the `$`-function does this `lapply(bah, \`$\`, 'call')` result in? It's apparently not `\`$\`(bah[[1L]], 'call')` which is how I seem to be reading that note (if you replace `...` with `'call'` and `FUN` with `\`$\``). – eddi Aug 13 '13 at 19:23
  • 4
    `\`$\`(bah[[1L]], ...)` – Peyton Aug 13 '13 at 19:29