Passing missing argument from function to function in R

前端 未结 4 1738
野性不改
野性不改 2020-12-31 04:13

I’ve learned that it’s common practice to use optional arguments in function and check them with missing() (e.g. as discussed in SO 22024082)

In this example round0

相关标签:
4条回答
  • 2020-12-31 04:15

    rlang provides also a function missing_arg() that makes an argument be missing.

    foo = function(a, round0) {
      a = a * pi
      if(!missing(round0)) round(a)
      else a
    }
    
    bar = function(b) {
      if(b > 10) round1 <- TRUE else round1 <- rlang::missing_arg()
      foo(b, round1)
    }
    
    foo(9)
    #> [1] 28.27433
    bar(9)
    #> [1] 28.27433
    

    Created on 2020-12-02 by the reprex package (v0.3.0)

    0 讨论(0)
  • 2020-12-31 04:17

    In your example, round0 isn't missing, it's set to round1 which is undefined (as opposed to missing).

    The best way in general of doing this is to use a default value, in your case FALSE:

    foo = function(a, round0 = FALSE) {
        a = a * pi
        if (!round0) round(a)
        else a
    }
    
    bar = function(b) {
        round1 <- FALSE
        if (b > 10) round1=TRUE
        foo(b, round1)
    }
    

    or where the default value cannot easily be expressed in the parameter list:

    foo = function(a, round0 = NULL) {
        a = a * pi
        if(!is.null(round0)) round(a)
        else a
    }
    
    bar = function(b) {
        round1 <- NULL
        if (b > 10) round1=TRUE
        foo(b, round1)
    }
    

    Note in both cases you need to set the parameter to be the default value manually in your calling function.

    You could also call your foo function with or without an argument if needed within your if statement:

    bar = function(b) {
        if (b > 10) foo(b, TRUE) else foo(b)
    }
    

    An alternative approach that shows how to generate a missing value is shown by @moody_mudskipper’s answer.

    0 讨论(0)
  • 2020-12-31 04:17

    You can create a missing object by using substitute() without argument.

    In your case we could make round1 a missing object in the else clause :

    foo = function(a, round0) {
      a = a * pi
      if(!missing(round0)) round(a)
      else a
    }
    
    bar = function(b) {
      if(b > 10) round1=T else round1 <- substitute()
      foo(b, round1)
    }
    
    bar(9)
    #> [1] 28.27433
    

    Created on 2019-10-24 by the reprex package (v0.3.0)

    0 讨论(0)
  • 2020-12-31 04:35

    I recently encountered a similar problem and wanted to solve it in a general way. I think it can be done as shown in the definition of the function g() below:

    f <- function(a = 5, b = 3, c = 2, d = 7) {
      if (missing(a)) {print("a is missing.")}
      if (missing(b)) {print("b is missing.")}
      if (missing(c)) {print("c is missing.")}
      if (missing(d)) {print("d is missing.")}
    
      cat(a, b, c, d)
    }
    
    g <- function(a = 1, b = 1, c = 1, d = 1) {
      args <- as.list(match.call())
      args[[1]] <- NULL # remove first list element, it's the function call
      do.call(f, args, envir = parent.frame())
    }
    

    Here is what we get when calling g() with different sets of arguments:

    > g()
    [1] "a is missing."
    [1] "b is missing."
    [1] "c is missing."
    [1] "d is missing."
    5 3 2 7
    
    > g(a = 3)
    [1] "b is missing."
    [1] "c is missing."
    [1] "d is missing."
    3 3 2 7
    
    > g(b = 10, c = 10)
    [1] "a is missing."
    [1] "d is missing."
    5 10 10 7
    

    You can add to or remove from the args list if you don't want to hand all arguments to the next function or want to add some. As an example, see the following function g() that does this in a general way:

    g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1) {
      f_args <- c("a", "b", "c") # arguments we want to hand off to function f
    
      # obtain the list of arguments provided
      args <- as.list(match.call())
      # remove first list element, it's the function call
      args[[1]] <- NULL
      # remove the arguments that are not listed in f_args
      args <- args[na.omit(match(f_args, names(args)))]
    
      # now add argument d, we always want it to be 0:
      args <- c(args, list(d = 0))
      do.call(f, args, envir = parent.frame())
    }
    

    Here is what we get when calling g() with different sets of arguments:

    > g()
    [1] "a is missing."
    [1] "b is missing."
    [1] "c is missing."
    5 3 2 0
    
    > g(a = 3)
    [1] "b is missing."
    [1] "c is missing."
    3 3 2 0
    
    > g(b = 10, c = 10)
    [1] "a is missing."
    5 10 10 0
    

    See this answer for additional information on do.call().

    0 讨论(0)
提交回复
热议问题