Skip to content

Functions returning functions

6 messages · Paulo Grahl, Romain Francois, Wacek Kusnierczyk +2 more

#
Dear All:

I have a question regarding the behavior of functions.
Say I define a function that returns another function :
A <- function(parameters) {
     # calculations w/ parameters returning 'y'
     tmpf <- function(x) { # function of 'y' }
     return(tmpf)
}

The value of the parameters are stored in an environment local to the
function. Then I call
x<- something
B<-A(x)

When R executes this last statement,  does it perform all the
calculations inside function A again (i.e., all the calculations that
yield 'y')
 or the value of 'y' is already stored in the function's local environment ?

Many thanks.
Paulo Gustavo Grahl, CFA
#
Paulo Grahl wrote:
no, see this:

 > f <- function( x = 3){
+    function( ){}
+ }
 > g <- f()
 > ls.str( environment(g) )
x :  num 3
 > h <- f(6)
 > ls.str( environment(h) )
x :  num 6
 > ls.str( environment(g) )
x :  num 3

See also colorRampPalette which uses this feature:

 > colorRampPalette
function (colors, ...)
{
    ramp <- colorRamp(colors, ...)
    function(n) {
        x <- ramp(seq.int(0, 1, length.out = n))
        rgb(x[, 1], x[, 2], x[, 3], maxColorValue = 255)
    }
}
<environment: namespace:grDevices>
 > pal <- colorRampPalette( c("blue", "white", "red") )
 > pal
function (n)
{
    x <- ramp(seq.int(0, 1, length.out = n))
    rgb(x[, 1], x[, 2], x[, 3], maxColorValue = 255)
}
<environment: 0x99aba4c>
 > ls.str( environment( pal ) )
colors :  chr [1:3] "blue" "white" "red"
ramp : function (x)

  
    
#
Paulo Grahl wrote:
consider this example:

    foo = function(a, b)
       function(c)
          if (c) a else b

    x = 1
    y = 2
    bar = foo(x, y)

    bar(TRUE)
    # 1
    x = 0
    bar(TRUE)
    # 1, not 0

    y = 0
    bar(FALSE)
    # 0, not 2

vQ
#
On Wed, May 20, 2009 at 7:48 AM, Wacek Kusnierczyk
<Waclaw.Marcin.Kusnierczyk at idi.ntnu.no> wrote:
The last one is due to lazy evaluation.  Try
repeating it with this variation:

   foo2 = function(a, b) {
	  force(a); force(b)
          function(c) if (c) a else b
   }

which forces a and b to be evaluated right away.
#
Romain Francois wrote:
... but there are ways around it

f <- function( x = 3 ){
    # y will be get a value the first time
    # the function created below is called
    delayedAssign( "y", {
        cat( "\nevaluating `y` right now\n" )
        x + 5
    } )
   
    # z will get a new value each time the function
    # created below is called
    makeActiveBinding( "z", function( data ){
        if( missing(data) ){
            cat( "\nevaluating `z` right now\n" )
            rnorm(x)
        }
    }, environment() )
       function( ){
          list( y, z )
       }
}

 > h <- f()
 > h()

evaluating `y` right now

evaluating `z` right now
[[1]]
[1] 8

[[2]]
[1]  1.0991189 -1.1033016 -0.5410733

 > h()

evaluating `z` right now
[[1]]
[1] 8

[[2]]
[1]  0.7102276 -0.6371956 -0.7703179

 > environment(h)[["z"]]

evaluating `z` right now
[1] -0.6713595  2.2006114  0.9335674
 > environment(h)[["z"]]

evaluating `z` right now
[1]  0.1243523  0.6178176 -0.9043380