r

How to have primitive discard additional arguments


I want to call a number of functions with na.rm = TRUE wherever applicable. I thought of Mapping the desired functions to do.call, but this would fail for length which accepts one argument only.

To make it work, I have to use an anonymous wrapper function to discard all but the accepted argument:

xs <- c(NA, 2:10)
  
list(mean = mean,
     n = \(., ...) length(.)
     ) |> 
  Map(f = \(fn) do.call(fn, list(xs, na.rm = TRUE))) 
$mean
[1] 6

$n
[1] 10

Is there some global setting to have functions ignore arguments they cannot accommodate?


Solution

  • No, there's no such global setting. You could make a helper that wraps a function with an na.rm option

    narm <- function(f) function(...) f(..., na.rm=TRUE)
    

    And then use

    list(mean=narm(mean), length=length) |> Map(f=\(fn) fn(xs))
    # or
    list(mean=mean |> narm(), length=length) |> Map(f=\(fn) fn(xs))
    

    Because many of the functions that support na.rm are primitive/generic functions, functions like args() won't work to tell if you if they suppose na.rm or not.

    you could also just drop the NA values

    list(mean=mean, length=length) |> Map(f=\(fn) fn(na.omit(xs)))
    

    which does change the length value, but you could probably special case that depending on what exactly your needs are. But it's misleading to think of 6 as being the mean of 10, values, it's the mean of the 9 non-missing values.

    You could also special case length in the na.rm helper, something like

    narm <- function(f) function(...) if (!identical(f, length)) f(..., na.rm=TRUE) else f(...)
    list(mean=mean, length=length) |> Map(f=\(fn) narm(fn)(xs))