[R] Evaluation of defaults in functions

Luke Tierney luke at stat.uiowa.edu
Fri Sep 29 17:12:44 CEST 2006


On Fri, 29 Sep 2006, Prof Brian Ripley wrote:

> On Thu, 28 Sep 2006, hadley wickham wrote:
>
>>>
>>> And, to answer the specific question: Yes, R has lazy evaluation,
>>> everywhere. Arguments are always evaluated if and when they are
>>> needed.
>>>
>>
>> But doesn't R has a rather limited force of lazy evaluation? - you
>> have no control over it, apart from that arguments are evaluated
>> lazily.  This rather limited compared to other languages (no lazy
>> lists etc)
>
> I'd say that was a rather pure form.

There are not all that many other languages that use lazy evaluation.
Those that do are for the most part pure or nearly pure functional
languages--Haskell is probably the main example.  These go much
further in their use of lazy evaluation than R.  For analogs of the R
expressions

         x <- f(x)
 	list(f(x))
         x + f(x)

only the last one is guaranteed to result in f being called. This
makes many things conceptually cleaner and also automatically supports
lazy data structures, which allows one to express things like infinite
sequences.  Some of the downsides are a more complex (or at least
very different) implementation and that I becomes very hard to reason
about performance.  One of the reasons performance is hard to sort out
is that it is (deliberately, because of the declarative nature of
these languages) hard to know exactly when an evaluation will occur.

Contrary to Hadley's comment R actually provides quite a lot of control since
assignments are guaranteed to cause evaluation, e.g. in

     g <- function(x) {
         x <- x # forces evaluation
         ...
     }

the argument is guaranteed to be evaluated.  The function force()
makes this a little more readable (avoids the need for a comment).

> However, Peter's statement is not quite true. R has several types of
> functions, and I think he is referring to closures, the functions written
> in R itself.  The argument handling in the built-in functions (primitive
> and .Internal) is different, and they will often evaluate all the
> arguments whether needed or not.

I think Peter's statement is OK with respect to evaluation since you
can think of `+` as being implemented as

     `+` <- function(x,y) {
         force(x)
         force(y)
         ... internal code to add x, y ...
     }

so y would be guaranteed to be evaluated even if the value of x would
cause the internal code to throw an error, for example (though not if
evaluation of x causes an error).  Builtins are of course different in
that they don't do argument matching, but that is another issue.

Lazy data structures can be implemented in R on top of the limited
lazy evaluation mechanism.  I experimented with this for fun a one
point.  Some code is in http://www.stat.uiowa.edu/~luke/R/lazy/.  This
is out of date but not too hard to fix.  Insuring memory efficiency is
still a bit tricky; some comments are int he notes at this site.

Best,

luke

-- 
Luke Tierney
Chair, Statistics and Actuarial Science
Ralph E. Wareham Professor of Mathematical Sciences
University of Iowa                  Phone:             319-335-3386
Department of Statistics and        Fax:               319-335-3017
    Actuarial Science
241 Schaeffer Hall                  email:      luke at stat.uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



More information about the R-help mailing list