Open In App

Abstraction in R Programming

Last Updated : 11 Nov, 2020
Improve
Improve
Like Article
Like
Save
Share
Report

People who’ve been using the R language for any period of time have likely grown to be conversant in passing features as arguments to other functions. However, people are a whole lot much less probably to go back functions from their personal custom code. This is simply too horrific because doing so can open up a whole new international of abstraction that may greatly lower the quantity and complexity of the code vital to finish sure styles of duties. Here we offer a few short examples of ways R programmers can make use of lexical closures to encapsulate both records and strategies.

Abstraction in R Programming

Implementation in R

To begin with, an easy instance, assume you want a function that provides add_2() to its argument. You could probably write something like this:

R




add_2 <- function(y) { 2 + y }


Which does precisely what you’ll anticipate:

> add_2(1:10)
[1] 3 4 5 6 7 8 9 10 11 12

Now suppose you need every other feature that rather provides 7 to its argument. The herbal issue to do could be to write down any other characteristic, much like add_2, where the 2 is replaced with a 7. But this would be grossly inefficient: if within the future you discover that you made a mistake and also you in truth want to multiply the values instead of adding them, you will be pressured to trade the code in places. In this trivial instance, that won’t be plenty of hassle, but for greater complicated projects, duplicating code is a recipe for catastrophe. A higher concept could be to put in writing a characteristic that takes one argument, x, that returns every other function which provides its argument, y, to x. In different words, something like this:

R




add_x <- function(x) {
   function(y) { x + y }
}


Now, while you name add_x with an argument, you may get back a feature that does precisely what you need:

R




add_2 <- add_x(2)
add_7 <- add_x(7)


> add_2(1:10)
[1] 3 4 5 6 7 8 9 10 11 12
> add_7(1:10)
[1] 8 9 10 11 12 13 14 15 16 17

So this doesn’t seem too earth-shattering. But if you look closely at the definition of add_x, you may notice something odd: how does the return characteristic realize in which to discover x when it’s referred to as at a later point?

It turns out that R is lexically scoped, which means that features deliver with them a connection with the environment within which they were described. In this case, when you call add_x, the x argument you offer receives attached to the environment for the return characteristic. In different phrases, on this simple instance, you may think about R as simply changing all instances of the x variable within the feature to be lower back with the value you specify whilst you known as add_x. Ok, so this may be a neat trick, however, how this can be used extra productively? For a slightly extra complicated instance, think you’re doing some complex bootstrapping, and, for efficiency, you pre-allocate container vectors to keep the results. This is easy if you have just a single vector of effects—all you need to do is take into account to iterate an index counter whenever you upload an end result to the vector.

R




for (i in 1:nboot) {
 bootmeans[i] <- mean(sample(data, length(data), 
                             replace = TRUE))
}


> mean(data)
[1] 0.0196
> mean(bootmeans)
[1] 0.0188

But think you need to track several extraordinary statistics, every requiring you to maintain track of a unique index variable. If your bootstrapping ordinary is even a little bit complicated, this could be tedious and vulnerable to blunders. By the use of closures, you may summary away all of this bookkeeping. Here is a constructor function that wraps a pre-allocated container vector:

R




make_container <- function(n) {
   x <- numeric(n)
   i <- 1
  
   function(value = NULL) {
       if (is.null(value)) {
           return(x)
       }
       else {
           x[i] <<- value
           i <<- i + 1
       }  
   }
}


When you call make_container with an issue, it pre-allocates a numeric vector of the specified period, n, and returns a feature that permits you to feature statistics to that vector while not having to fear approximately keeping the music of an index. If you don’t the argument to that return feature is NULL, the entire vector is the lower back.

R




bootmeans <- make_container(nboot)
  
for (i in 1:nboot)
bootmeans(mean(sample(data, length(data), 
                      replace = TRUE)))


> mean(data)
[1] 0.0196
> mean(bootmeans())
[1] 0.0207

Here make_container is tremendously easy, but it may be as complicated as you need. For example, you could want to have the constructor function carry out some expensive calculations which you could instead no longer do on every occasion the character is known as. In reality, that is what I even have completed within the boolean3 package deal to decrease the range of calculations performed at each new release of the optimization habitual.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads