From luke-tierney at uiowa.edu  Tue Feb 24 16:50:37 2015
From: luke-tierney at uiowa.edu (luke-tierney at uiowa.edu)
Date: Tue, 24 Feb 2015 09:50:37 -0600
Subject: [Rd] iterated lapply
In-Reply-To: <20150224113908.GA7612@cs.toronto.edu>
References: <mailman.21.1424775604.19275.r-devel@r-project.org>
	<20150224113908.GA7612@cs.toronto.edu>
Message-ID: <alpine.DEB.2.02.1502240950150.2336@luke-Latitude>

The documentation is not specific enough on the indented semantics in
this situation to consider this a bug. The original R-level
implementation of lapply was

     lapply <- function(X, FUN, ...) {
         FUN <- match.fun(FUN)
         if (!is.list(X))
         X <- as.list(X)
         rval <- vector("list", length(X))
         for(i in seq(along = X))
         rval[i] <- list(FUN(X[[i]], ...))
         names(rval) <- names(X)           # keep `names' !
         return(rval)
     }

and the current internal implementation is consistent with this. With
a loop like this lazy evaluation and binding assignment interact in
this way; the force() function was introduced to help with this.

That said, the expression FUN(X[[i]], ...) could be replaced by

     local({
         i <- i
         list(FUN(X[[i]], ...)
     })

which would produce the more desirable result

     > sapply(test, function(myfn) myfn(2))
     [1] 2 4 6 8

The C implementation could use this approach, or could rebuild the
expression being evaluated at each call to get almost the same semantics.
Both would add a little overhead. Some code optimization might reduce
the overhead in some instances (e.g. if FUN is a BUILTIN), but it's
not clear that would be worth while.

Variants of this issue arise in a couple of places so it may be worth
looking into.

Best,

luke

On Tue, 24 Feb 2015, Radford Neal wrote:

> From: Daniel Kaschek <daniel.kaschek at physik.uni-freiburg.de>
>> ... When I evaluate this list of functions by
>> another lapply/sapply, I get an unexpected result: all values coincide.
>> However, when I uncomment the print(), it works as expected. Is this a
>> bug or a feature?
>>
>> conditions <- 1:4
>> test <- lapply(conditions, function(mycondition){
>>   #print(mycondition)
>>   myfn <- function(i) mycondition*i
>>   return(myfn)
>> })
>>
>> sapply(test, function(myfn) myfn(2))
>
> From: Jeroen Ooms <jeroenooms at gmail.com>
>> I think it is a bug. If we use substitute to inspect the promise, it
>> appears the index number is always equal to its last value:
>
> From: Duncan Temple Lang <dtemplelang at ucdavis.edu>
>> Not a bug, but does surprise people. It is lazy evaluation.
>
>
> I think it is indeed a bug.  The lapply code saves a bit of time by
> reusing the same storage for the scalar index number every iteration.
> This amounts to modifying the R code that was used for the previous
> function call.  There's no justification for doing this in the
> documentation for lapply.  It is certainly not desired behaviour,
> except in so far as it allows a slight savings in time (which is
> minor, given the time that the function call itself will take).
>
>   Radford Neal
>
> ______________________________________________
> R-devel at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>

-- 
Luke Tierney
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-tierney at uiowa.edu
Iowa City, IA 52242                 WWW:  http://www.stat.uiowa.edu



[Rd] iterated lapply
luke-tierney at uiowa.edu