Skip to content

What I like about R is that it takes its inspiration from Scheme. Being a functional programming language, R indeed supports the idea of closures. What are they? This is my attempt to unravel the mystery about closures.

First what closures are not. Some writers have confused this notion with that of algebraic closures. Functional programming closures have nothing to do with algebraic closures. Don’t you believe it if  you get told it came from Group Theory. It does not. An algebraic closure is a property of an algebraic structure. Namely if $a, b \in G$ and $\bullet$ is an operation in $G$, then $a \bullet b \in G$. In other words the result of applying the operation on the members of $G$, is also a member in $G$. This says that $G$ is closed under the operation $\bullet$, whatever that operation may be.

Functional programming closures have something to do with how the language should handle free variables in relation to functions. Since functional programming takes its cue from lambda calculus, let us define what free variables are in this  computational system. It is best done by an example below:

Consider $\lambda x.yx$. In this expression, $y$ is free as it is not controlled by the lambda symbol, but $x$ is bound because $\lambda$ is enclosing that $x$, as we read from left to right. This is where the functional programming (FP) closures come from. FP closures tell us how it will handle those free variables when they occur in a function definition. The way this is explained in FP is in the area of environments and R have those too. Simply put when a function is defined, the system remembers that state of the environment where and when that function is defined. In other words, it remembers the declarations made inside the function such as names of variables and nested functions declared inside it.

The best way I think this is illustrated is in the way FP closures mimic classes in OOP languages. Look at this code.

make_bal<- function (){
val <- 0
bal <- function (method){
add_method <- function(x){
val <<- val + x
}
get_method <- function() {
val
}
if (method == "dep") {
add_method
}
else {
get_method
}
}
bal
}

In R, the label “function” acts as our lambda declaration. In line 2, val is a free variable because it is not defined as an argument of the function. In line 4, x is bound. It is defined as a parameter in the function definition of add_method. However val is not accessible outside make_bal because it is defined inside it and so we could say it is a  “closed” to the outside world. In line 5 we use the <<- operator similar to set! in Scheme. That operator will hunt for val up the environment chain and will get the first one it finds which is in line 2.

So let us ask R to load our make_bal.

> account<-make_bal()
> account("get")()
[1] 0
> account("dep")(50)
> account("get")()
[1] 50
> account("dep")(50)
> account("get")()
[1] 100
> withdraw<-account("dep")
> withdraw(-50)
> account("get")()
[1] 50



In 1, we define a function from it, and call it account. In 2, we check that val is starting at 0. In 4, we made a deposit of 50. Each time we make a deposit, our balance increases as seen in line 8. Finally we can define a function called withdraw provided the amount we pass is always negative and as can be seen when we call it in line 13, the balance has been reduced by the amount we took out of our balance.

One can see that in an FP like R, the notion of classes will not be missed because closures handle that need.

As usually happens in computer science, computer scientists borrow notions from mathematics and this use of the term “closures” is one of them. Then also as it usually happens, it produces negative consequences, rather than clarify sometimes it confuses people in the process. It would have been better had computer scientists chosen a different term.

Credits: Andy Balaam’s Scheme Closure.

Advertisements
No comments yet