[R] functional (?) programming in r

Stavros Macrakis macrakis at alum.mit.edu
Mon Nov 17 23:19:57 CET 2008


I think when people say that R semantics are derived from Scheme, all
they mean is that R supports lexical closures.  But R has other
features which are very un-Scheme-like, and when they interact with
lexical closures, you get behavior you don't find in other functional

R passes function arguments using a "promise" mechanism somewhat
similar to Algol 60's call-by-name, but caching the result when it is
evaluated, what is sometimes called call-by-need.  If the argument
value is not needed, it keeps it as a "promise" (what Algol 60 called
a "thunk").

Thus, we have:

            lapply(1:5,function(i) function( ) i )[[1]]() => 5

since the inner i is actually bound to a 'promise' which seems to
point to the variable used by lapply for counting.

Compare with the result of:

            lapply(1:5,function(i) { i<-i; function() i } )[[1]]() => 1

Scheme of course does not have the "promise" mechanism so this doesn't happen.

I'm new to R, so I don't know if this is considered a bug or a feature.


On Mon, Nov 17, 2008 at 4:28 PM, Wacek Kusnierczyk
<Waclaw.Marcin.Kusnierczyk at idi.ntnu.no> wrote:
> the following is a trivialized version of some functional code i tried
> to use in r:
> (funcs = lapply(1:5, function(i) function() i))
> # a list of no-parameter functions, each with its own closure environment,
> # each supposed to return the corresponding index when applied to no
> arguments
> sapply(funcs, function(func) func())
> # supposed to return c(1,2,3,4,5)
> there is absolutely nothing unusual in this code, in the context of
> functional programming.
> the following is my best translation to python (modulo indexing, which
> is inessential), where it does what i wanted:
> funcs = map(lambda i: lambda: i, range(5))
> map(lambda func: func(), funcs)
> # [0,1,2,3,4]
> all these functions have distinct environments:
> (envs = sapply(funcs, function(func) environment(func)))
> assign("i", 0, environment(envs[[1]]))
> sapply(funcs, function(func) func())
> interestingly, identical says they are all unequal, but compare disagrees.
> check = function(equal) for (i in 1:4) for (j in i:4+1)
> print(equal(envs[[i]], envs[[j]]))
> check(identical)
> check(compare)
> compare seems to cast environments to character; for identical, the docs
> give an example where environments are compared, but compare fails
> (i.e., succeeds) miserably (the docs do not warn not to compare
> environments):
> e1 = new.env(parent=emptyenv())
> e2 = new.env(parent=emptyenv())
> assign("foo", "bar", e1)
> compare(e1, e2)
> # oops?
> back to the original example, how come?
> vQ
> ----
> for those curious, try the following in python:
> map(lambda func: func(), [lambda: i for i in range(5)])
> map(lambda func: func(), (lambda: i for i in range(5)))
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.

More information about the R-help mailing list