blue-sky
blue-sky

Reputation: 53826

How to define a closure?

Here I'm attempting to define a closure that contains a function which can be invoked :

myFirstClosure <- function (){

  var1 = 1;

  f1 <- function() {
    var1
  }

}

m <- myFirstClosure()
m.f1()

Error is returned : Error: could not find function "m.f1"

Why is the inner scoped function f1 not accessible as I have defined the outer scoped function myFirstClosure ?

Update :

Is it meaningless to invoke closures like :

myFirstClosure <- function (){

  var1 = 1;
  var2 = 0;

  f1 <- function() {
    var1
  }

  f2 <- function() {
    var2
  }

}

As f1 and f2 cannot be invoked independently ?

Upvotes: 0

Views: 150

Answers (4)

blue-sky
blue-sky

Reputation: 53826

This achieves the behavior I'm looking for :

myFirstClosure <- function() {

  var1 <- 1;
  var2 <- 0;

  list(f1=function() { 
    var1
  },f2=function() { 
    var2
  })
}

m <- myFirstClosure()
m$f1()
m$f2()

This aided in finding solution https://www.r-bloggers.com/using-closures-as-objects-in-r/ as well as answers / comments for this question.

Upvotes: 2

Rui Barradas
Rui Barradas

Reputation: 76450

You cannot use that form, m.f1() because that's not Rsyntax. You can use a similar form, with environments. Something like the following.

myFirstClosure <- function (){
    var1 <- 1
    e <- environment(myFirstClosure)
    e$f1 <- function() {
        var1
    }
    e
}

m <- myFirstClosure()
m$f1()
#[1] 1

Note however that myFirstClosure would then return an environment, not a closure. This probably defeats your original goal.
See also An Introduction to R, section 10.7 Scope, the open.account example for another way of doing something like what you seem to want.

EDIT.
To answer to the question's edit by the OP, and repeating the code above a bit, the example above can be extended to any number of functions.

myFirstClosure <- function (){
    var1 <- 1
    var2 <- 0
    e <- environment(myFirstClosure)
    e$f1 <- function() {
        var1
    }
    e$f2 <- function() {
        var2
    }
    e
}

m <- myFirstClosure()
m$f1()
#[1] 1

m$f2()
#[1] 0

Upvotes: 3

alex.h
alex.h

Reputation: 128

The simplest answer here is that you have defined your closure on m itself, and need to simply invoke m

myFirstClosure <- function (){

  var1 = 1;

  f1 <- function() {
    var1
  }

}

m <- myFirstClosure()
m()

I just ran this and it outputs 1 as you desire.

I am aware that you are hoping to do something slightly different - your code reminds me of the closure-as-module pattern in javascript, where your closure-creating function outputs an object with multiple functions that can be called individually as attributes, all with a closure on variables internal to the creating function.

I don't want to say that this is impossible with R but I am not aware of how to do it. I am interested to see if other commentors can suggest a way.

Incidentally dot-to-access attribute syntax is mostly (entirely?) not available in r - usually you will use the $ syntax, but that also won't work in this instance.

Upvotes: 0

Gregor Thomas
Gregor Thomas

Reputation: 145785

. is meaningless in R (except for S3 method dispatch, but that's not relevant here), and the fact that the returned function was once called f1 in the environment of the function that created it is not retained. As soon as you assign myFirstClosure() to m,

m <- myFirstClosure()

its name is m and nothing else. You can call it with m().

For additional reading, I'd suggest the Functional Programming chapters of Advanced R.

Upvotes: 6

Related Questions