I’m aware that NULL values in lists can sometimes trip people up. I’m curious why in a specific instance lapply and rapply seem to treat NULL values differently.
l <- list(a = 1, c = NULL, d = 3)
lapply(l,is.null)
$a
[1] FALSE
$c
[1] TRUE
$d
[1] FALSE
So far so good. How about if we do the exact same thing with rapply?
rapply(l, is.null, how = "replace")
$a
[1] FALSE
$c
list()
$d
[1] FALSE
This example is very simple and non-recursive, but you see the same behavior in rapply with nested lists.
My question is why? If, as advertised in ?rapply, it is a ‘recursive version of lapply’, why do they behave so differently in this case?
I think you answered your own question: because it’s recursive.
You don’t often see this, but
NULLcan actually be used to indicate an empty sequence, because it is the emptypairlist(similar to how()in Scheme terminates a list. Internally, R is very scheme like).So,
rapplyrecurses into the empty list, but doesn’t bother turning it back into a pairlist when it’s done; you get a regular empty list.Actually,
rapplyandlapplydon’t really treat NULL that differently:And you can see in the R source code (memory.c) that this is exactly how pairlists are meant to work: