Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R lazy evaluation paradox (R bug?)

I have multiple functions handing around arguments that may be missing.

e.g. i have

mainfunction <- function(somearg) {
    mytest(somearg)
    fun <- function() { subfunction(somearg) }
    fun()
}

with the interesting aspect that the only interaction of mytest(somearg) with the arg is that it tests if the argument isn’t missing:

mytest = function(somearg) {
    print(missing(somearg))
}

subfunction then again tests if it’s missing and treats it accordingly:

subfunction = function(somearg) {
    if (missing(somearg))
        somearg = NULL
    else
        somearg = matrix(somearg, cols = 2)
    # somearg is used here…
}

the kicker is that, with somearg missing, this doesn’t work: matrix(somearg, cols = 2) throws

argument "somearg" is missing, with no default

during debugging, i found the following:

  1. at the start of mainfunction, missing(somearg) returns TRUE
  2. in mytest, missing(somearg) returns TRUE
  3. insubfunction, missing(somearg) returns FALSE (!!!!)

therefore the matrix branch is hit, but in reality, somearg is missing, so it fails…

wat.

like image 298
flying sheep Avatar asked Mar 27 '15 09:03

flying sheep


People also ask

What is lazy evaluation in R?

Lazy evaluation is implemented in R as it allows a program to be more efficient when used interactively: only the necessary symbols are evaluated, that is to say that only the needed objects will be loaded in memory and/or looked for.

What is lazy evaluation in functional programming?

Lazy evaluation is perhaps the most powerful tool for modularization in the functional programmer’s repertoire. Lazy evaluation (or call-by-need) delays evaluating an expression until it is actually needed; when it is evaluated, the result is saved so repeated evaluation is not needed.

What are semantics in R language?

These semantics are described in R language definition R language definition: The mechanism is implemented via promises. When a function is being evaluated the actual expression used as an argument is stored in the promise together with a pointer to the environment the function was called from.


1 Answers

the @BenBolker way:

mainfunction <- function(somearg = NULL) {
    mytest(somearg)
    fun <- function() { subfunction(somearg) }
    fun()
}

mytest = function(somearg) {
    print(is.null(somearg))
}

subfunction = function(somearg) {
    if (is.null(somearg))
        somearg = 1:10
    else
        somearg = matrix(somearg, ncol = 2)
   somearg
}

Another way, using explicit missing argument

mainfunction <- function(somearg) {
    is_missing <- missing(somearg)
    mytest(is_missing)
    fun <- function() { subfunction(somearg, is_missing) }
    fun()
}
mytest = function(x) {  print(x) }
subfunction = function(somearg, is_arg_missing) {
    if (is_arg_missing)
        somearg = 1:10
    else
        somearg = matrix(somearg, ncol = 2)
   somearg
}

A third way, using plain missing arg passing:

    mainfunction <- function(somearg) {
        is_missing <- missing(somearg)
        mytest(somearg)
        fun <- function() { 
          if (is_missing) subfunction() else 
              subfunction(somearg) 
        }
        fun()
    }

    mytest = function(somearg) {
        print(missing(somearg))
    }

    subfunction = function(somearg) {
        if (missing(somearg))
            somearg = 1:10
        else
            somearg = matrix(somearg, ncol = 2)
       somearg
    }
like image 119
Karl Forner Avatar answered Oct 30 '22 03:10

Karl Forner