Bug 16093 - Reduce on functions broken due to recursive assignment and lazy evaluation
Summary: Reduce on functions broken due to recursive assignment and lazy evaluation
Status: CLOSED FIXED
Alias: None
Product: R
Classification: Unclassified
Component: Low-level (show other bugs)
Version: R 3.1.1
Hardware: x86_64/x64/amd64 (64-bit) Linux
: P5 major
Assignee: R-core
URL:
Depends on:
Blocks:
 
Reported: 2014-11-28 23:51 UTC by Vitalie Spinu
Modified: 2017-07-27 21:04 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Vitalie Spinu 2014-11-28 23:51:20 UTC
Due to lazy evaluation (#13861 and #14004) and re-assignment in Reduce, reducing on functions makes them capture themselves instead of the actual argument.  

Try a simple function composition:


f <- function(x) x

f1 <- function(h) {
    function(x) paste("f1", h(x))
}

rf <- Reduce(function(f, h) f(h), list(f1), init = identity, right = T)
rf("start")
## ->  Error: evaluation nested too deeply: infinite recursion

Second order `f` captures itself instead of the argument `h` on recursive assignment. Simple example:

f <- f1(f)
f("start")
## ->  Error: evaluation nested too deeply: infinite recursion

identical(f, environment(f)$h)
## [1] TRUE

It works fine with:

f2 <- f1(f)
f2("start")


In Reduce it's on line 23:

╭──────── #23 ─ Reduce.R ──
│         if (right) {
│             for (i in rev(ind)) init <- f(x[[i]], init)
│         }
╰──────── #25 ─

Now that I know the problem, I can easily fix it by `force`, but it takes a while to figure out what's going on.

--- 
BTW, Would be really nice to have a Compose function in the `funprog` set.
Comment 1 Luke Tierney 2015-03-18 19:38:46 UTC
Resolved in R-devel by r68010.
Comment 2 Benjamin Tyner 2017-07-27 17:01:04 UTC
Did r68010 change the semantics in particular with regard to unevaluated expressions? Compare under R < 3.2,

   > str(lapply(list(a=10,b=10,c=10), function(x) substitute(x)))
   List of 3
   $ a: language X[[1L]]
   $ b: language X[[2L]]
   $ c: language X[[3L]]

versus under R >= 3.2,

   > str(lapply(list(a=10,b=10,c=10), function(x) substitute(x)))
   List of 3
   $ a: language X[[i]]
   $ b: language X[[i]]
   $ c: language X[[i]]
Comment 3 Luke Tierney 2017-07-27 19:51:55 UTC
Yes - now more consistent with others, e.g.

> str(apply(matrix(1:2), 1,function(x) substitute(x)))
List of 2
$ : language newX[, i]
$ : language newX[, i]

in both	R versions.
Comment 4 Benjamin Tyner 2017-07-27 21:04:08 UTC
Thanks Luke. Is there a way to mimic the prior lapply functionality? I tried using forceAndCall but with no success; per the help page, it only works with closures (whereas substitute is primitive).