r super assignment operator

Secure Your Spot in Our PCA Online Course - Register Until Feb. 29 (Click for More Info)

Joachim Schork Image Course

Assignment Operators in R (3 Examples) | Comparing = vs. <- vs. <<-

On this page you’ll learn how to apply the different assignment operators in the R programming language .

The content of the article is structured as follows:

Let’s dive right into the exemplifying R syntax!

Example 1: Why You Should Use <- Instead of = in R

Generally speaking, there is a preference in the R programming community to use an arrow (i.e. <-) instead of an equal sign (i.e. =) for assignment.

In my opinion, it makes a lot of sense to stick to this convention to produce scripts that are easy to read for other R programmers.

However, you should also take care about the spacing when assigning in R. False spacing can even lead to error messages .

For instance, the following R code checks whether x is smaller than minus five due to the false blank between < and -:

A properly working assignment could look as follows:

However, this code is hard to read, since the missing space makes it difficult to differentiate between the different symbols and numbers.

In my opinion, the best way to assign in R is to put a blank before and after the assignment arrow:

As mentioned before, the difference between <- and = is mainly due to programming style . However, the following R code using an equal sign would also work:

In the following example, I’ll show a situation where <- and = do not lead to the same result. So keep on reading!

Example 2: When <- is Really Different Compared to =

In this Example, I’ll illustrate some substantial differences between assignment arrows and equal signs.

Let’s assume that we want to compute the mean of a vector ranging from 1 to 5. Then, we could use the following R code:

However, if we want to have a look at the vector x that we have used within the mean function, we get an error message:

Let’s compare this to exactly the same R code but with assignment arrow instead of an equal sign:

The output of the mean function is the same. However, the assignment arrow also stored the values in a new data object x:

This example shows a meaningful difference between = and <-. While the equal sign doesn’t store the used values outside of a function, the assignment arrow saves them in a new data object that can be used outside the function.

Example 3: The Difference Between <- and <<-

So far, we have only compared <- and =. However, there is another assignment method we have to discuss: The double assignment arrow <<- (also called scoping assignment).

The following code illustrates the difference between <- and <<- in R. This difference mainly gets visible when applying user-defined functions .

Let’s manually create a function that contains a single assignment arrow:

Now, let’s apply this function in R:

The data object x_fun1, to which we have assigned the value 5 within the function, does not exist:

Let’s do the same with a double assignment arrow:

Let’s apply the function:

And now let’s return the data object x_fun2:

As you can see based on the previous output of the RStudio console, the assignment via <<- saved the data object in the global environment outside of the user-defined function.

Video & Further Resources

I have recently released a video on my YouTube channel , which explains the R syntax of this tutorial. You can find the video below:

The YouTube video will be added soon.

In addition to the video, I can recommend to have a look at the other articles on this website.

  • R Programming Examples

In summary: You learned on this page how to use assignment operators in the R programming language. If you have further questions, please let me know in the comments.

assignment-operators-in-r How to use different assignment operators in R – 3 R programming examples – R programming language tutorial – Actionable R programming syntax in RStudio

Subscribe to the Statistics Globe Newsletter

Get regular updates on the latest tutorials, offers & news at Statistics Globe. I hate spam & you may opt out anytime: Privacy Policy .

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Post Comment

Joachim Schork Statistician Programmer

I’m Joachim Schork. On this website, I provide statistics tutorials as well as code in Python and R programming.

Statistics Globe Newsletter

Get regular updates on the latest tutorials, offers & news at Statistics Globe. I hate spam & you may opt out anytime: Privacy Policy .

Related Tutorials

Calculate Derivative of Expression in R (Example) | deriv() Function

Calculate Derivative of Expression in R (Example) | deriv() Function

Force R to Show Scientific Notation (2 Examples)

Force R to Show Scientific Notation (2 Examples)

Beginning Computer Science with R

14 functional programming in r.

It was simple, but you know, it’s always simple when you’ve done it.

In this Chapter we aren’t going to cover any fundamentally new R powers. Instead we’ll get acquainted with just one aspect of a computer programming paradigm known as functional programming . We will examine a set of R-functions for which functions themselves are supplied as arguments. These functions allow us to accomplish a great deal of computation in rather concise and expressive code. Not only are they useful in R itself, but they help you to reason abstractly about computation and prepare you for functional-programming aspects of other programming languages.

14.1 Programming Paradigms

Let us begin by exploring the notion of a programming paradigm in general. We will go on in this Chapter to consider two programming paradigms for which R provides considerable support. In the next Chapter we will consider a third programming paradigm that exists in R.

A programming paradigm is a way to describe some of the features of programming languages. Often a paradigm includes principles concerning the use of these features, or embodies a view that these features have special importance and utility in good programming practice.

14.1.1 Procedural Programming

One of the older programming paradigms in existence is procedural programming . It is supported in many popular languages and is often the first paradigm within which beginners learn to program. In fact, if one’s programming does not progress beyond a rudimentary level, one may never become aware that one is working within the procedural paradigm—or any paradigm at all, for that matter.

Before we define procedural programming, let’s illustrate it with an example. Almost any of the programs we have written so far would do as examples; for specificity, let’s consider the following snippet of code that produces from the data frame m111survey a new, smaller frame consisting of just the numerical variables:

By now there is nothing mysterious about the above code-snippet. What we want to become conscious of is the approach we have taken to the problem of selecting the numerical variables. In particular, observe that:

  • We worked throughout with data , some of which, like m111survey , was given to us and some of which we created on our own to help solve the problem. For example, we created the variable cols . Note also the very helpful index-variable i in the for -loop. We set up the data structure isNumerical in order to hold a set of data ( TRUE s and FALSE s).
  • We relied on various procedures to create data and to manipulate that data in order to produce the desired result. Some of the procedures appeared as special blocks of code—most notably the for -loop. Other procedures took the form of functions. As we know, a function encapsulates a useful procedure so that it can be easily reused in a wide variety of circumstances, without the user having to know the details of how it works. We know that names() will give us the vector of names of the columns of m111survey , that length() will tell us how many names, there are, that is.numeric() will tell us whether or not a given variable in m111survey is a numerical variable, and so on. The procedures embodied in these functions were written by other folks and we could examine them if we had the time and interest, but for the most part we are content simply to know how to access them.

Procedural programming is a paradigm that solves problems with programs that can be broken up into collections of variables, data structures and procedures. In this paradigm, there is a sharp distinction between variables and data structures on the one hand and procedures on the other. Variables and data structures are data —they are the “stuff” that a program manipulates to produce other data, other “stuff.” Procedures do the manipulating, turning stuff into other stuff.

14.2 The Functional Programming Paradigm

Let us now turn to the second of the two major programming paradigms that we study in this Chapter: Functional Programming.

14.2.1 The Ubiquity of Functions in R

Let’s a bit more closely at our code snippet. Notice how prominently functions figure into it, on nearly every line. In fact, every line calls at least one function! This might seem unbelievable: after all, consider the line below:

There don’t appear to be any functions being called, here! But in fact two functions get called:

The so-called assignment operator <- is actually a function in disguise: the more official—albeit less readable—form of variable <- value is:

Thus, to assign the value 3 to that variable a one could write:

The sub-setting operator for vectors [ , more formally known as extraction (see help(Extract) ) is also a function. The expression m111survey[, isNumerical] is actually the following function-call in disguise:

Indeed functions are ubiquitous in R. This is part of the significance of the following well-known remark by a developer of S, the precursor-language of R:

“To understand computations in R, two slogans are helpful:

  • Everything that exists is an object.
  • Everything that happens is a function call.”

—John Chambers

The second slogan indicates that functions are everywhere in R. It also corresponds to the first principle of the functional programming paradigm, namely:

Computation is regarded as the evaluation of functions.

14.2.2 Functions as First-Class Citizens

So functions are ubiquitous in R. Another interesting thing about them is that even though they seem to be associated with procedures—after all, they make things happen—they are, nevertheless, also objects. They are data, or “stuff” if you like.

This may not seem obvious at first. But look at the following code, where you can ask what type of thing a function is:

The so-called “primitive” functions of R—the functions written not in R but in C-code—are “built in” objects. On the other hand, consider this user-defined function:

Functions other than primitive functions are objects of type “closure.” 34

If a function can be a certain type of thing, then it must be a “thing”—an object, something you can manipulate. For example, you can put functions in a list:

Very importantly, you can make functions serve as argument for other functions, and functions can return other functions as their results. The following example demonstrates both of these possibilities.

In fact, in R functions can be treated just like any variable. In computer programming, we say that such functions are first-class citizens .

Although it is not often stated as a separate principle of the functional programming paradigm it is true that in languages that provide support for functional programming, the following principle holds true:

Functions are first-class citizens.

14.2.3 Minimize Side Effects

In the code-snippet under consideration, we note that there are two types of functions:

  • functions that return a value;
  • functions that provide output to the console or make a change in the Global Environment.

Example of the first type of function included:

  • seq_along()
  • is.numeric()
  • the extraction-function `[`()

A function that produced output to the console was str() .

The assignment function `<-`() added cols , isNumerical and numsm111 to the Global Environment, and also made changes to isNumerical in the course of the for -loop.

Of course we have seen examples of functions that do two of these things at once, for example:

In computer programming, output to the console, along with changes of state —changes to the Global Environment or to the file structure of your computer—are called side-effects . Functions that only return values and do not produce side-effects are called pure functions.

A third principle of the functional programming paradigm is:

Functions should be pure.

Now this principle is difficult to adhere to, and in fact if you were to adhere strictly to it in R then your programs would never “do” anything. There do exist quite practical programming languages in which all of the functions are pure—and this leads to some very interesting features such as that the order in which operations are evaluated doesn’t affect what the function returns—but these “purely functional” languages manage purity by having other objects besides functions produce the necessary side-effects. In R we happily let our functions have side-effects: we certainly want to do some assignment, and print things out to the console from time to time.

One way that R does support the third principle of functional programming is that it makes it easy to avoid having your functions modify the Global Environment. To see this consider the following example:

This is as we expect: the variable heavenly_ash exists only in the run-time environment that is created in the call to add_three() . As soon as the function finishes execution that environment dies, and heavenly_hash dies long with it. In particular, it never becomes part of the Global Environment.

If you really want your functions to modify the Global Environment—or any environment other than its run-time environment, for that matter—then you have to take special measures. You could, for example, use the super-assignment operator <<- :

The super-assignment operator looks for the name heavenly_hash in the parent environment of the run-time environment, If if finds heavenly_hash there then it changes its value to 5 and stops. Otherwise it looks in the next parent up, and so on until it reaches the Global Environment, at which point if it doesn’t find a heavenly_hash it creates one and gives it the value. In the example above, assuming you ran the function from the console, the parent environment is the Global Environment and the function has made a change to it: a side-effect.

Except in the case of explicit assignment functions like `<-`() , changes made by functions to the Global Environment can be quite problematic. After all, we are used to using functions without having to look inside them to see how they do their work. Even if we once wrote the function ourselves, we may not remember how it works, so if it creates side effects we may not remember that it does, and calling them could interfere with other important work that the program is doing. (If the program already has heavenly_hash in the Global Environment and the we call a function that changes it value, we could be in for big trouble.) Accordingly, R supports the third principle of functional programming to the extent of making it easy for you to avoid function calls that change your Global Environment.

14.2.4 Procedures as Higher-Order Function Calls

The last principle of the functional programming paradigms that we will state here isn’t really a formal principle: it is really more an indication of the programming style that prevails in languages where functions are first-class objects and that provide other support for functional programming. The final principle is:

As much as possible, procedures should be accomplished by function calls, In particular, loops should be replaced by calls to higher-order functions.

A higher-order function is simply a function that takes other functions as arguments. R provides a nice set of higher-order functions, many of which substitute for iterative procedures such as loops. In subsequent sections we will study the some of the most important higher-order functions, and see how they allow us to express some fairly complex procedures in a concise and readable way. You will also see how this style really blurs the distinction—so fundamental to procedural programming—between data and procedures. In functional programming, functions ARE data, and procedures are just function calls.

14.2.5 Functional Programming: A Summary

For our purposes, the principles of the functional programming paradigm are as follows:

  • Computation consists in the evaluation of functions.
  • Functions are first-class citizens in the language.
  • Functions should only return values; they should not produce side-effects. (At the very least they should not modify the Global Environment unless they are dedicated to assignment in the first place.)
  • As much as possible, procedures should be written in terms of function calls. In particular, loops should be replaced by calls to higher-order functions.

14.3 purrr Higher-Order Functions for Iteration

In the remainder of the Chapter we will study important higher-order functions: functions that take a function as an argument and apply that function to each element of another data structure. As we have said previously, such functions often serve as alternatives to loops.

The higher-order functions we study come from the package purrr , which is attached whenever we load the tidy-verse.

14.3.1 map() and Variations

Suppose that we want to generate five vectors, each of which consists of ten numbers randomly chosen between 0 and 1. We accomplish the task with a loop, as follows:

If we wanted the vectors to have length \(1, 4, 9, 16,\) and 25, then we could write:

In the first example, the elements in the vector 1:5 didn’t matter—we wanted a vector of length ten each time—and in the second case the elements in the 1:5 did matter, in that they determined the lengths of the five vectors produced. Of course in general we could apply runif() to each element of any vector at all, like this:

If we can apply runif() to each element of a vector, why not apply an arbitrary function to each element? That’s what the function map() will do for us. The general form of map() is:

In the template above:

  • .x can be a list or any atomic vector;
  • .f is a function that is to be applied to each element of .x . In the default operation of map() , each element of .x becomes in turn the first argument of .f .
  • ... consists of other arguments that are supplied as arguments for the .f function, in case you have to set other parameters of the function in order to get it to perform in the way you would like.

The result is always a list.

With map() we can get the list in our second example as follows:

If we had wanted the random numbers to be between—say—4 and 8, then we would supply extra arguments to runif() as follows:

The default behavior of map() is that the .x vector supplies the first argument of .f . However, if some ... parameters are supplied then .x substitutes for the first parameter that is not mentioned in ... . In the above example, the min and max parameters are the second and third parameters for runif() so .x substitutes for the first parameter—the one that determines how many random numbers will be generated. In the example below, the vector lower_bounds substitutes for min , the second parameter of runif() :

Sometimes we wish to vary two or more of the parameters of function. In that case we use pmap() . The first parameter of pmap() is named .l and takes a list of vectors (or lists). For example:

Observe that pmap() knows to interpret the first element of the input-list—the vector how_many as giving the values of the first argument of runif() . The second parameter of runif() ( min ) is set at 0, so pmap() deduces that upper_bounds —the second element of the input-list—gives the values for the next next parameter in line, the parameter max .

One might just as well use pmap() to vary all three parameters:

The .f parameter can be any function, including one that you define yourself. Here’s an example:

You could also set f to be a function that you write on the spot, without even bothering to give it a name:

In computer programming a function is called anonymous when it is not the value bound to some name. .

map() allows a shortcut for defining anonymous functions. The above call could have been written as:

The ~ indicates that the body of the function is about to be begin. The . stands for the parameter of the function.

When we introduced map() we said that .x was a vector or a list, In fact .x could be an object that can be coerced into a list. Hence it is quite common to use map() with the data frames: the frame is turned into a list, each element of which is a column of the frame. Here is an example:

Note that the elements of the returned list inherit the names of the input data frame. This holds for any named input:

When the result can take on a form more simple than a list, it is possible to use variants of map() such as:

Thus we could obtain a named integer vector of the number of NA -values for each variable in m11survey as follows:

Here are the types of each variable:

Here is a statement of whether or not each variable is a factor:

14.3.2 walk() and Variations

walk() is similar to map() , but is used when we are interested in producing side-effects. It applies its .f argument to each element of .x is was given, but also returns the .x in case we want to pipe it into some other function.

Here we use walk() only for its side-effect: we re-write a familiar function to print a pattern to the Console without using a loop.

The next example illustrates the use of the return-value of walk() . We would like to save plots of all numerical variables from the data frame m111survey , and also print summaries of them to the Console.

First we create a directory to hold the plots:

Next, we get the numerical variables in m111survey :

We used purrr::keep() , which retains only the elements of its input .x such that its second argument .p ( a function that returns a single TRUE or FALSE ) returns TRUE .

We will also need the names of the numerical variables:

We need a function to save the density plot of a single numerical variable:

We also need a function to produce a summary of a single numerical variable:

Now we walk through the process. We will actually use the function pwalk() , which will take the following inputs:

  • .x (a list with two elements: the data frame of numerical variables and the vector of the names of these variables), and
  • .f (the function saveGraph , to make and save a density plot)

We also use pmap_dfr() , which takes a list consisting of the data frame and variable-names and constructs a data frame row-by-row, with each row summarizing one of the variables.

Check the plots directory; it should contain these files:

  • density_diff.ideal.act.png
  • density_fastest.png
  • density.GPA.png
  • density_height.png
  • density_ideal_ht.png
  • density_sleep.png

14.3.3 Example: Flowery Meadow Redux

In Section 4.3.3.1 we simulated people walking through a meadow, picking flowers until they had picked a desired number of flowers of a desired color. In Section 9.3.3 we used lists to store the results of such a simulation. Now we’ll see how to store the results as a data frame.

First, we modify the helper-function that simulates one person picking flowers so that, instead of returning a vector of colors, it returns a data frame:

Note that the new function takes an extra parameter person , the name of the person picking the flowers.

Let’s try it out:

Now we write the function to make the data frame of results for a group of people. pmap() will come in handy.

Here are the results:

14.3.4 Practice Exercises

Use map() to produce a list of the squares of the whole numbers from 1 to 10.

Use map_dbl() to produce a numerical vector of the squares of the whole numbers from 1 to 10.

Use map_chr to state the type of each element of the following list:

Here are some people:

The following vector tells whether or not each person is a Grand Poo-Bah:

Use pwalk() to properly greet each person. The result in the console should be as follows:

14.3.5 Solutions to the Practice Exercises

This is more verbose, but works just as well:

Again the more verbose approach works just as well:

14.4 Other purrr Higher-Order Functions

14.4.1 keep() and discard().

keep() is similar to dplyr ’s filter() , but whereas filter() chooses rows of a data frame based on a given condition, keep() chooses the elements of the input list or vector .x based on a condition named .p .

discard(.x,, . p = condition) is equivalent to keep(.x, .p = !condition) . Thus:

14.4.2 reduce()

Another important member of the purrr family is reduce() . Given a vector .x and a function .f that takes two inputs, reduce() does the following:

  • applies f to elements 1 and 2 of .x , getting a result;
  • applies f to the result and to element 3 of .x , getting another result;
  • applies f to this new result and to element 4 of .x , getting yet another result …
  • … and so on until all of the elements of .x have been exhausted.
  • then reduce() returns the final result in the above series of operations.

For example, suppose that you want to add up the elements of the vector:

Of course you could just use:

After all, sum() has been written to apply to many elements at once. But what if addition could only be done two numbers at a time? How might you proceed? You could:

  • add the 3 and 1 of (the first two elements of vec ), getting 4;
  • then add 4 to 4, the third element of vec , getting 8;
  • then add 8 to 6, the final element of vec , getting 14;
  • then return 14.

reduce() operates in this way.

Can you see how reduce() gets its name? Step by step, it “reduces” its .x argument, which may consist of many elements, to a single value.

A common application of reduce() is to take an operation that is defined on only two items and extend it to operate on any number of items. Consider, for example, the function intersect() , , which will find the intersection of any two vectors of the same type:

You cannot intersect three or more vectors at once:

With reduce() you can intersect as many vectors as you like, provided that they are first stored in a list.

You can write your own function to supply as the argument for .f , but it has to be able to operate on two arguments. reduce() will take the first argument of the .f function to be what has been “accumulated” so far, and the second argument of the .f function—the value to be combined with what has been accumulated—will be provided by the current element of .x .

As a simple example, let’s write our own reduce-summer in a way that shows the user the reduction process at work:

When you write your own .f function, it’s a good idea to use names for the parameters that remind you of their role in the reduction process. acc (for “accumulated”) and curr (for “current”) are used above.

reduce() can take an argument called .init . When this argument is given a value, operation begins by applying to .f to .init and the first element of .x . For example:

14.4.2.1 An Extended Example of Reduction

Let’s apply reduce() with .init to the task of making a truth table : the set of all \(2^n\) logical vectors of a given length \(n\) .

The set \(S_1\) of vectors of length \(n = 1\) consists of only two vectors:

Now consider a systematic way to construct the set \(S_2\) of all the vectors of length two. We know that there are four such vectors:

Observe that the first two of them begin with TRUE and end with the set \(S_1\) of vectors of length one:

The last two of them begin with FALSE and also end with \(S_1\) :

Now consider \(S_3\) , the set of all eight vectors of length three:

Observe that the first four of them end begin with TRUE and and with the vectors of \(S_2\) :

The last four of them begin with FALSE and also end with the vectors of \(S_2\) :

The pattern is now clear. If for any \(m \ge 1\) you are in possession of the \(2^m \times m\) matrix \(S_m\) of all possible vectors of length \(m\) , then to obtain the \(2^{m+1} \times (m+1)\) matrix \(S_{m+1}\) of all possible vectors of length \(m+1\) you should:

  • stack \(2^m\) TRUE s on top of \(2^m\) FALSE s, creating a \(2^{m+1} \times 1\) matrix \(U\) ;
  • stack the \(S_m\) underneath itself, creating a \(2^{m+1} \times m\) matrix \(V\) ;
  • place \(U\) next to \(V\) .

reduce() with .init set to \(S_1\) is appropriate for this iterative building process. Here is an implementation:

We have included a verbose option so we can watch the process as it unfolds.

Note also that the parameters for the .f function are named:

  • acc (what has been “accumulated” up to the current step), and
  • value (the value of .x at the current step).

It’s conventional to give these or similar names to the parameters of the building-function.

Of course in practice we would not turn on the verbose option:

14.4.3 Practice Exercises

The operator * (multiplication) is really a function:

But it can only multiply two numbers at once. The R-function prod() cna handle as many numbers as you like:

Use reduce() and * to write your own function product() that takes a numerical vector vec and returns the product of the elements of the vector. It should work liek this:

( Hint : in the call to reduce() you will have to the refer to the * -function as `*` .)

Modify the function product() so that it in a single call to reduce() it multiplies the number 2 by the product of the elements of vec . ( Hint : set .init to an appropriate value.)

The data frame iris gives information on 150 irises. Use keep() to create a new data frame that includes only the numerical variables having a mean greater than 3.5.

14.4.4 Solutions to the Practice Exercises

The following does not work. Why?

14.5 Functionals vs. Loops

The higher-order functions we have studied in this chapter are often called functionals. As we pointed out earlier, they deliver results that could have been produced by a writing a loop of some sort.

Once you get used to functionals, you will find that they are often more “expressive” than loops—easier for others to read and to understand, and less prone to bugs. Also, many of them are optimized by the developers of R to run a bit faster than an ordinary loop written in R.

For example, consider the following list. It consists of ten thousand vectors, each of which contains 100 randomly-generated numbers.

If we want the mean of each vector, we could write a loop:

Or we could use map_dbl() :

Comparing the two using system.time() , on my machine I got:

For the loop, I get:

The map-function is a bit faster, but the difference is small.

Remember also that vectorization is much faster than looping, and is also usually quite expressive, so don’t struggle to take a functional approach when vectorization is possible. (This advice applies to a several examples from this Chapter, in which the desired computations had already been accomplished in earlier chapters by some form of vectorization.)

14.6 Conclusion

In this Chapter we have concentrated on only a single aspect of the Functional Programming paradigm: exploiting the fact that functions are first-class citizens in R, we studied a number of higher-order functions that can substitute for loops. There is certainly a great deal more to Functional Programming than the mere avoidance of loops, but we’ll end our study at this point. Familiarity with higher-order functions will stand you in good stead when you begin, in subsequent courses on web programming, to learn the JavaScript language. JavaScript makes constant use of higher-order functions!

A programming paradigm that solves problems with programs that can be broken up into collections of variables, data structures and procedures. This paradigm tends to draw a sharp distinction between variables and data structures on the one hand and procedures on the other.

A programming paradigm that stresses the central role of functions. Some of its basic principles are:

  • Functions should only return values; they should not produce side-effects.
  • As much as possible, procedures should be written in terms of function calls.

A function that does not produce side-effects.

A change in the state of the program (i.e., a change in the Global Environment) or any interaction external to the program (i.e., printing to the console).

A function that takes another function as an argument.

A function that does not have a name.

The act of rewriting computer code so that it performs the same task as before, but in a different way. (This is usually done to make the code more human-readable or to make it perform the task more quickly.)

Links to Class Slides

Quarto Presentations that I sometimes use in class:

  • Sections 14.1 - 14.2
  • Sections 14.3 - 14.4

r super assignment operator

Explain in words what the following line of code produces when given a numerical vector y :

In the course of your explanation, say whether the result is a vector or a list.

Which do you think works faster for a given numerical vector y ? This code:

Or this code?

Justify your answer with a convincing example, using system.time() . What moral do you draw from this?

To refactor computer code is to rewrite the code so that it does the same thing, but in a different way. We might refactor code in order to make it more readable by humans, or to make it perform its task more quickly.

Refactor the following code so that it uses keep() instead of a loop:

The following function produces a list of vectors of uniform random numbers, where the lower and upper bounds of the numbers are given by the arguments to the parameters lower and upper respectively, and the number of vectors in the list and the number of random numbers in each vector are given by a vector supplied to the parameter vecs .

Refactor the code for random_sims() so that it uses map() instead of a loop.

The following enhanced version of randomSims() is even more flexible, as it allows both the upper and lower limits for the randomly-generated numbers to vary with each vector of numbers that is produced.

Use pmap() to refactor the code for random_sims2() so as to avoid using the loop.

Supposing that y is a numerical vector, explain in words what the following code produces:

Write a line of code using the sub-setting operator [ that produces the same result as the code in the previous problem.

Use keep() to write a function called odd_members() that, given any numerical vector, returns a vector containing the odd numbers of the given vector. Your function should take a single argument called vec , the given vector. A typical example of use would be as follows:

You are given the following list of character vectors:

Use reduce() and the union() function to obtain a character vector that is the union of all the vectors in lst .

Remember the function subStrings() from the exercises of the Chapter on Strings? Refactor it so that it does EXACTLY the same thing but makes no use of loops.

Solve Part One of Advent of Code 2022 Day 3 . Save your input file in your submit folder with the filename input_aoc_2022-03.txt , and read in the input data, naming it input , using the following code:

Solve Part One of Advent of Code 2022 Day 25 . Save your input file in your submit folder with the filename input_aoc_2022-25.txt , and read in the input data, naming it input , using the following code:

( Hint : The snafu numbering-system bears some relationship to base-5 numbering. After reviewing Section 11.4 , write two helper-functions: one to convert numbers to “base-snafu” and another to convert base-snafu representations to numbers.)

Reading between the parentheses

Scoping in R

2019-09-10 :: scope , r

By: Ming-Ho Yee

In the previous post of this three-part blog series, we discussed lexical and dynamic scope. Now, in this second part, we can return to the original question: is R lexically or dynamically scoped?

Recall the example program from before:

Let’s examine what happens when we run this example. First, we create a mapping for x in the top-level environment. On line 2, we define a function f , which returns the value of some x . On line 3, we define a function g , which creates a new mapping for x , and then calls f . Note that the assignment on line 4 does not update the definition on line 1.

When f is called, it needs to look up the value of x . In other words, does the reference of x on line 2 refer to the assignment on line 1 or the assignment on line 4? If f returns 1 , then the behaviour matches lexical scoping. If it returns 2 , then the behaviour matches dynamic scoping.

When we run this example, the result is 1 . This implies that R is lexically scoped.

But there’s more to this story. In the rest of this blog post, I’ll examine some interesting scoping examples in R, and discuss how the scoping definitions relate to R.

The next and final part of this blog series, published simultaneously with this one, is an appendix where I implement four different scoping disciplines in R.

R is lexically scoped, but…

In Evaluating the Design of the R Language , 1 Morandat, Hill, Osvald, and Vitek write:

As is often the case, R is lexically scoped up to the point it is not. R is above all a dynamic language with full reflective access to the running program’s data and representation.

In other words, R provides many different “escape hatches”—ways to bypass lexical scoping. Additionally, even without escape hatches, some of R’s functionality can be surprising.

Functions, environments, and variables in R

Before we look at some examples, I think it’s useful to briefly discuss some of the core concepts in R that relate to scoping.

Functions. R has first-class functions, and functions evaluate to closures. In other words, a function value includes both the body of the function as well as the environment that the function was evaluated in. In R, the programmer can modify the environment of a closure. Note that R is function scoped; there is no block scoping.

Environments. An environment in R is a mapping from variables to values. Each function has its own local environment. Furthermore, each environment has a reference to the “enclosing” environment that it was evaluated in. R environments are first-class, meaning the programmer can add, modify, or removing variable mappings, and also change the reference to the enclosing environment.

Variable lookup. When R looks up a variable, it will search in the current environment for a mapping. If no mapping is found, then it will search in the enclosing environment. This process continues until a mapping is found, or the topmost, empty environment is reached, in which case an error is raised.

Variable assignment. <- is the variable assignment operator in R. The expression x <- 1 assigns the value 1 to the variable x in the current environment. If a mapping for x already exists in the environment, then the assignment will update and overwrite the existing value. Otherwise, a new mapping is created in the environment. Note that variable assignment can only update the current environment, and never creates a scope.

From this description, we can see that R implements lexical scoping (or at least, something that behaves a lot like lexical scoping): each function value is associated with the environment it was evaluated in, and variable lookup proceeds along the chain of enclosing environments. In fact, the creators of R have confirmed that lexical scoping was their intent. 2

On the other hand, variable lookup depends on the run-time state of the program—names cannot be resolved statically. Furthermore, since R provides operations for environment manipulation, a programmer can easily circumvent lexical scoping.

The following examples will make this clear.

Adding variable mappings at run time

When f is called, it creates a function g that returns x , assigns 2 to x , and then calls g . When g is called, it looks up x . Since no mapping is found in g ’s environment, it searches in the enclosing environment ( f ’s), and finds that x has value 2 . Therefore, g returns 2 .

Note that the x on line 3 is resolved only when function g is called, not when it is defined. However, when g is defined, its environment has a reference to f ’s environment. Therefore, as long as x is defined before g is called, the lookup will always succeed.

Here’s a second example:

f is a function that branches on its argument, b . If b evaluates to true, then the expression x <- 2 is evaluated, and a mapping for x is created in f ’s environment. Otherwise, no mapping is created.

When we look up the value of x on line 5, R will first search the function’s environment. If b evaluated to true, then R will find a value for x , which is 2 . Otherwise, R will search in the enclosing environment of f , and find that x is 1 .

Both of these examples vaguely resemble dynamic scoping, in that x takes the value of the most recent assignment. However, this is not how R is implemented, and it is not consistent with how R behaves in other examples.

Function lookup

R has slightly different lookup rules, if the variable is in function call position. Specifically, R will search the environment chain and skip non-function values.

In this example, we call g with the argument 42 , which is not a function. Then, in the body of g , we call f(0) on line 3, which requires looking up f . Although there is an f in the environment of g , its value is 42 , which is not a function. R will then search the enclosing environment, where it finds the function defined on line 1. Therefore, the lookup on line 3 resolves to the function on line 1, so f(0) returns 0 .

This behaviour exists because c is the built-in function that constructs vectors (in other words, one of the most commonly used functions in R), but it is also a commonly used argument name.

Super assignment

<<- is the “super assignment” operator. It skips the current environment and then searches the chain of enclosing environments until it finds a variable to update. If no variable is found, then a new mapping is created at the top environment.

In the above program, we define x to be 0 at the top level, and then define the function f . When we call f on line 7, it assigns 1 to x on line 3, which creates a mapping in the local environment. On line 4, the super assignment skips the mapping in the local environment and instead updates the mapping created on line 1. Next, f returns x , which is looked up from the local environment and has value 1 . Finally, line 8 looks up x from the top level environment, which has value 2 .

Evaluating arbitrary code

R has a mechanism for converting an arbitrary string to code and then executing it. On line 3, we parse and evaluate the argument t , which happens to be the string "x <- 0" . Then, when line 4 executes, the lookup of x returns 0 .

Simulating dynamic scope

On line 3, we perform an explicit variable lookup for x , but we do so in the environment parent.frame() , which refers to the calling function’s environment, in this case, g ’s environment.. Therefore, the lookup returns 2 .

Note that R has a similarly named function, parent.env(e) which returns the enclosing environment of the given environment e .

Constructing an arbitrary environment

When f is called, it constructs a new environment, e , which is initially empty. (By default, its enclosing environment is the current environment, which is f ’s.) Next, on line 4, it directly adds a mapping to that environment, assigning 3 to x . Then, on line 5, the lookup is explicitly done in environment e , so f returns 3 .

Deleting mappings

Not only is it possible to dynamically add and modify mappings in R, but it is also possible to delete mappings. This is what line 3 does: it explicitly removes the mapping for x from the enclosing environment of the current environment. In other words, the definition on line 1 is deleted. Therefore, when f is called, the lookup of x fails and an error is raised.

Infinite loop during variable lookup

In this final example, manipulation of environments allows us to create a function where variable lookup results in an infinite loop.

On lines 1 and 2, we create new, empty environments. Both have the same enclosing environment, which is the top-level environment. However, on lines 3 and 4, we modify their enclosing environments to create a cycle: enva ’s enclosing environment is envb , and envb ’s enclosing environment is enva .

On line 5, we define a function with a free variable, x , but on line 6, we set f ’s environment to be enva . Finally, we call f .

When the body of f is evaluated, it needs to look up x . Lookup starts in f ’s environment, which we set to be enva . Since no mapping for x is found, lookup continues in enva ’s enclosing environment, which is envb . However, envb is also empty, so lookup continues in its enclosing environment, which is enva , and now lookup results in an infinite loop.

An intuition for scoping in R

Some of the above examples appear to demonstrate dynamic scoping. Recall two of our examples:

It seems that x takes on the value of the last assignment, but we know this is not the case, from the first example. This is also not how R is implemented. What’s missing from our intuition?

The key insight is that R is function scoped . In R, each function has an associated environment, and that environment implements a scope. In general, only a function definition can create a scope. Therefore, the assignment operator <- does not create a new scope , and it is more useful to think of it as a mutation on the current environment . (In contrast, in most languages, a variable binding or definition creates a new scope, and an assignment mutates that variable.)

In a sense, it might be more accurate to say that R environments are lexically scoped, variables are scoped to functions (but a reference can occur syntactically before a definition), and variable assignment is an update to the environment.

All of this might make you a little uncomfortable, and uncertain about R’s scoping rules.

On one hand, R passes the first example program as a lexically scoped language, the implementation of closures and variable lookup imply “lexical-like” behaviour, and the creators have confirmed that lexical scoping was the intent.

On the other hand, variable lookup depends on the run-time state of the program, and variable bindings cannot be resolved statically. Some of the examples even resemble dynamic scoping, where a free variable takes the value of the most recent assignment—but this is not consistent with R’s behaviour in other examples. Furthermore, the dynamic nature of R and its reflection and metaprogramming capabilities allow programmers to completely circumvent lexical scoping.

This ambiguity shows up in a paper, 3 where the authors write:

Furthermore, because variable scoping in R is dynamic and can be modified at the language level […] it cannot be trivially guaranteed that x is going to point to the same data structure throughout the entire execution of the loop.

It is true that a variable x may not point to the same data structure during the execution of a loop. It is true that scoping in R can be modified at the language level.

It is true that variable lookup is dynamic, as it is performed at run time and depends on the run-time program state. If that is your definition of dynamic scope , then it would be fair to say that R is dynamically scoped.

But if your definition of dynamic scope is “a variable is bound to the most recent assignment during the program’s execution,” then it is not correct to say R is dynamically scoped.

I think we have this ambiguity because scope (the places in a program where a variable can be referenced) and variable lookup or name resolution (determining which binding or definition a name refers to) are often considered together. For most lexically scoped languages, name resolution can be done at compile time. For most dynamically scoped languages, name resolution must be done at run time. R is lexically scoped, but must perform name resolution at run time.

Personally, I prefer the definition of scope that treats name resolution as an orthogonal issue. I think it is more useful to keep the two issues separate. In addition, I think it is confusing and unhelpful to say that R is both lexically and dynamically scoped, or that R is neither lexically and dynamically scoped.

I think it is more helpful to treat R as a lexically scoped language (with certain exceptions and surprises) than as a dynamically scoped language—when I read and write R code, I find it more convenient to think about nested function definitions and free variables in terms of lexical scoping rules. And I think that it is more accurate, based on the design and implementation, to classify R as a lexically scoped language.

Regardless, it is very easy to miscommunicate, so I think it’s important to be very clear and make sure you and your audience know what definitions of scoping you’re using!

This entire adventure started when we were working on a paper, 4 and asked each other, is R lexically or dynamically scoped? Eventually, it became apparent that we had different definitions of lexical and dynamic scope, so of course we were unable to agree on an answer!

This got me interested in exploring definitions of scope, the history of lexical scope, and how R fits with traditional definitions of lexical scope. The result was this mini blog series.

To summarize, I would say that scope refers to the places in a program where a variable is visible and can be referenced. Under lexical scoping , the scope of a variable is determined by the lexical ( i.e. , textual) structure of a program. Under dynamic scoping , a variable is bound to the most recent value assigned to that variable, i.e. , the most recent assignment during the program’s execution.

I would say that R aims to be lexically scoped—it was part of the design and implementation, but certain features make the situation more complicated. In particular, variables are function scoped, definitions do not introduce new scopes, and variable lookup is performed at run time. Furthermore, the dynamic nature of R and its metaprogramming capabilities allow programmers to completely circumvent lexical scoping.

Finally, there are some definitions of lexical and dynamic scope that also consider variable lookup. Under these definitions, R might be considered a dynamically scoped language, since variable lookup happens at run time. Therefore, it is important to be precise about your definitions!

If you want more content about R and scoping, the third and final part of this blog series is already published. In it, I walk through four different examples of using metaprogramming to simulate different scoping disciplines in R.

Edited 2020/02/21: For another discussion on R environments and lookups, (and also packages and namespaces, which I did not cover in my post), this blog post has some nice examples and diagrams.

I would like to thank Sam Caldwell, Guido Chari, Oli Flückiger, Aviral Goel, Ben Greenman, Jakob Hain, Jan Ječmen, Hugo Musso Gualandi, Artem Pelenitsyn, and Jan Vitek for their comments, feedback, and discussions that have greatly improved and shaped this blog post.

If you liked this post, you may also be interested in the following Twitter threads about R: one , two and three .

F. Morandat, B. Hill, L. Osvald, J. Vitek. “Evaluating the Design of the R Language,” in Proceedings of the European Conference on Object-Oriented Programming (ECOOP) , 2012. [ DOI ][ Available online ]  ↩

R. Gentleman and R. Ihaka. “Lexical Scope and Statistical Computing”, Journal of Computational and Graphical Statistics , vol. 9, no. 3, 2000. [ DOI ][ Available online ]  ↩

L. Stadler, A. Welc, C. Humer, and M. Jordan. “Optimizing R Language Execution via Aggressive Speculation,” in Proceedings of the Symposium on Dynamic Languages (DLS) , 2016. [ DOI ]  ↩

O. Flückiger, G. Chari, J. Ječmen, M.-H. Yee, J. Hain, and J. Vitek. “R Melts Brains: An IR for First-Class Environments and Lazy Effectful Arguments,” in Proceedings of the Symposium on Dynamic Languages (DLS) , 2019. To appear. [ Available online ]  ↩

(Show comments / Powered by Disqus)

10 Function factories

10.1 introduction.

A function factory is a function that makes functions. Here’s a very simple example: we use a function factory ( power1() ) to make two child functions ( square() and cube() ):

Don’t worry if this doesn’t make sense yet, it should by the end of the chapter!

I’ll call square() and cube() manufactured functions , but this is just a term to ease communication with other humans: from R’s perspective they are no different to functions created any other way.

You have already learned about the individual components that make function factories possible:

In Section 6.2.3 , you learned about R’s first-class functions. In R, you bind a function to a name in the same way as you bind any object to a name: with <- .

In Section 7.4.2 , you learned that a function captures (encloses) the environment in which it is created.

In Section 7.4.4 , you learned that a function creates a new execution environment every time it is run. This environment is usually ephemeral, but here it becomes the enclosing environment of the manufactured function.

In this chapter, you’ll learn how the non-obvious combination of these three features leads to the function factory. You’ll also see examples of their usage in visualisation and statistics.

Of the three main functional programming tools (functionals, function factories, and function operators), function factories are the least used. Generally, they don’t tend to reduce overall code complexity but instead partition complexity into more easily digested chunks. Function factories are also an important building block for the very useful function operators, which you’ll learn about in Chapter 11 .

Section 10.2 begins the chapter with an explanation of how function factories work, pulling together ideas from scoping and environments. You’ll also see how function factories can be used to implement a memory for functions, allowing data to persist across calls.

Section 10.3 illustrates the use of function factories with examples from ggplot2. You’ll see two examples of how ggplot2 works with user supplied function factories, and one example of where ggplot2 uses a function factory internally.

Section 10.4 uses function factories to tackle three challenges from statistics: understanding the Box-Cox transform, solving maximum likelihood problems, and drawing bootstrap resamples.

Section 10.5 shows how you can combine function factories and functionals to rapidly generate a family of functions from data.

Prerequisites

Make sure you’re familiar with the contents of Sections 6.2.3 (first-class functions), 7.4.2 (the function environment), and 7.4.4 (execution environments) mentioned above.

Function factories only need base R. We’ll use a little rlang to peek inside of them more easily, and we’ll use ggplot2 and scales to explore the use of function factories in visualisation.

10.2 Factory fundamentals

The key idea that makes function factories work can be expressed very concisely:

The enclosing environment of the manufactured function is an execution environment of the function factory.

It only takes few words to express these big ideas, but it takes a lot more work to really understand what this means. This section will help you put the pieces together with interactive exploration and some diagrams.

10.2.1 Environments

Let’s start by taking a look at square() and cube() :

It’s obvious where x comes from, but how does R find the value associated with exp ? Simply printing the manufactured functions is not revealing because the bodies are identical; the contents of the enclosing environment are the important factors. We can get a little more insight by using rlang::env_print() . That shows us that we have two different environments (each of which was originally an execution environment of power1() ). The environments have the same parent, which is the enclosing environment of power1() , the global environment.

env_print() shows us that both environments have a binding to exp , but we want to see its value 56 . We can do that by first getting the environment of the function, and then extracting the values:

This is what makes manufactured functions behave differently from one another: names in the enclosing environment are bound to different values.

10.2.2 Diagram conventions

We can also show these relationships in a diagram:

r super assignment operator

There’s a lot going on this diagram and some of the details aren’t that important. We can simplify considerably by using two conventions:

Any free floating symbol lives in the global environment.

Any environment without an explicit parent inherits from the global environment.

r super assignment operator

This view, which focuses on the environments, doesn’t show any direct link between cube() and square() . That’s because the link is the through the body of the function, which is identical for both, but is not shown in this diagram.

To finish up, let’s look at the execution environment of square(10) . When square() executes x ^ exp it finds x in the execution environment and exp in its enclosing environment.

r super assignment operator

10.2.3 Forcing evaluation

There’s a subtle bug in power1() caused by lazy evaluation. To see the problem we need to introduce some indirection:

What should square(2) return? You would hope it returns 4:

Unfortunately it doesn’t because x is only evaluated lazily when square() is run, not when power1() is run. In general, this problem will arise whenever a binding changes in between calling the factory function and calling the manufactured function. This is likely to only happen rarely, but when it does, it will lead to a real head-scratcher of a bug.

We can fix this problem by forcing evaluation with force() :

Whenever you create a function factory, make sure every argument is evaluated, using force() as necessary if the argument is only used by the manufactured function.

10.2.4 Stateful functions

Function factories also allow you to maintain state across function invocations, which is generally hard to do because of the fresh start principle described in Section 6.4.3 .

There are two things that make this possible:

The enclosing environment of the manufactured function is unique and constant.

R has a special assignment operator, <<- , which modifies bindings in the enclosing environment.

The usual assignment operator, <- , always creates a binding in the current environment. The super assignment operator , <<- rebinds an existing name found in a parent environment.

The following example shows how we can combine these ideas to create a function that records how many times it has been called:

r super assignment operator

When the manufactured function is run i <<- i + 1 will modify i in its enclosing environment. Because manufactured functions have independent enclosing environments, they have independent counts:

r super assignment operator

Stateful functions are best used in moderation. As soon as your function starts managing the state of multiple variables, it’s better to switch to R6, the topic of Chapter 14 .

10.2.5 Garbage collection

With most functions, you can rely on the garbage collector to clean up any large temporary objects created inside a function. However, manufactured functions hold on to the execution environment, so you’ll need to explicitly unbind any large temporary objects with rm() . Compare the sizes of g1() and g2() in the example below:

10.2.6 Exercises

The definition of force() is simple:

Why is it better to force(x) instead of just x ?

Base R contains two function factories, approxfun() and ecdf() . Read their documentation and experiment to figure out what the functions do and what they return.

Create a function pick() that takes an index, i , as an argument and returns a function with an argument x that subsets x with i .

Create a function that creates functions that compute the i th central moment of a numeric vector. You can test it by running the following code:

What happens if you don’t use a closure? Make predictions, then verify with the code below.

What happens if you use <- instead of <<- ? Make predictions, then verify with the code below.

10.3 Graphical factories

We’ll begin our exploration of useful function factories with a few examples from ggplot2.

10.3.1 Labelling

One of the goals of the scales package is to make it easy to customise the labels on ggplot2. It provides many functions to control the fine details of axes and legends. The formatter functions 57 are a useful class of functions which make it easier to control the appearance of axis breaks. The design of these functions might initially seem a little odd: they all return a function, which you have to call in order to format a number.

In other words, the primary interface is a function factory. At first glance, this seems to add extra complexity for little gain. But it enables a nice interaction with ggplot2’s scales, because they accept functions in the label argument:

r super assignment operator

10.3.2 Histogram bins

A little known feature of geom_histogram() is that the binwidth argument can be a function. This is particularly useful because the function is executed once for each group, which means you can have different binwidths in different facets, which is otherwise not possible.

To illustrate this idea, and see where variable binwidth might be useful, I’m going to construct an example where a fixed binwidth isn’t great.

r super assignment operator

Here each facet has the same number of observations, but the variability is very different. It would be nice if we could request that the binwidths vary so we get approximately the same number of observations in each bin. One way to do that is with a function factory that inputs the desired number of bins ( n ), and outputs a function that takes a numeric vector and returns a binwidth:

r super assignment operator

We could use this same pattern to wrap around the base R functions that automatically find the so-called optimal 58 binwidth, nclass.Sturges() , nclass.scott() , and nclass.FD() :

r super assignment operator

10.3.3 ggsave()

Finally, I want to show a function factory used internally by ggplot2. ggplot2:::plot_dev() is used by ggsave() to go from a file extension (e.g.  png , jpeg etc) to a graphics device function (e.g.  png() , jpeg() ). The challenge here arises because the base graphics devices have some minor inconsistencies which we need to paper over:

Most have filename as first argument but some have file .

The width and height of raster graphic devices use pixels units by default, but the vector graphics use inches.

A mildly simplified version of plot_dev() is shown below:

10.3.4 Exercises

  • Compare and contrast ggplot2::label_bquote() with scales::number_format()

10.4 Statistical factories

More motivating examples for function factories come from statistics:

  • The Box-Cox transformation.
  • Bootstrap resampling.
  • Maximum likelihood estimation.

All of these examples can be tackled without function factories, but I think function factories are a good fit for these problems and provide elegant solutions. These examples expect some statistical background, so feel free to skip if they don’t make much sense to you.

10.4.1 Box-Cox transformation

The Box-Cox transformation (a type of power transformation ) is a flexible transformation often used to transform data towards normality. It has a single parameter, \(\lambda\) , which controls the strength of the transformation. We could express the transformation as a simple two argument function:

But re-formulating as a function factory makes it easy to explore its behaviour with stat_function() :

r super assignment operator

In general, this allows you to use a Box-Cox transformation with any function that accepts a unary transformation function: you don’t have to worry about that function providing ... to pass along additional arguments. I also think that the partitioning of lambda and x into two different function arguments is natural since lambda plays quite a different role than x .

10.4.2 Bootstrap generators

Function factories are a useful approach for bootstrapping. Instead of thinking about a single bootstrap (you always need more than one!), you can think about a bootstrap generator , a function that yields a fresh bootstrap every time it is called:

The advantage of a function factory is more clear with a parametric bootstrap where we have to first fit a model. We can do this setup step once, when the factory is called, rather than once every time we generate the bootstrap:

I use rm(mod) because linear model objects are quite large (they include complete copies of the model matrix and input data) and I want to keep the manufactured function as small as possible.

10.4.3 Maximum likelihood estimation

The goal of maximum likelihood estimation (MLE) is to find the parameter values for a distribution that make the observed data most likely. To do MLE, you start with a probability function. For example, take the Poisson distribution. If we know \(\lambda\) , we can compute the probability of getting a vector \(\mathbf{x}\) of values ( \(x_1\) , \(x_2\) , …, \(x_n\) ) by multiplying the Poisson probability function as follows:

\[ P(\lambda, \mathbf{x}) = \prod_{i=1}^{n} \frac{\lambda ^ {x_i} e^{-\lambda}}{x_i!} \]

In statistics, we almost always work with the log of this function. The log is a monotonic transformation which preserves important properties (i.e. the extrema occur in the same place), but has specific advantages:

The log turns a product into a sum, which is easier to work with.

Multiplying small numbers yields even smaller numbers, which makes the floating point approximation used by a computer less accurate.

Let’s apply a log transformation to this probability function and simplify it as much as possible:

\[ \log(P(\lambda, \mathbf{x})) = \sum_{i=1}^{n} \log(\frac{\lambda ^ {x_i} e^{-\lambda}}{x_i!}) \]

\[ \log(P(\lambda, \mathbf{x})) = \sum_{i=1}^{n} \left( x_i \log(\lambda) - \lambda - \log(x_i!) \right) \]

\[ \log(P(\lambda, \mathbf{x})) = \sum_{i=1}^{n} x_i \log(\lambda) - \sum_{i=1}^{n} \lambda - \sum_{i=1}^{n} \log(x_i!) \]

\[ \log(P(\lambda, \mathbf{x})) = \log(\lambda) \sum_{i=1}^{n} x_i - n \lambda - \sum_{i=1}^{n} \log(x_i!) \]

We can now turn this function into an R function. The R function is quite elegant because R is vectorised and, because it’s a statistical programming language, R comes with built-in functions like the log-factorial ( lfactorial() ).

Consider this vector of observations:

We can use lprob_poisson() to compute the (logged) probability of x1 for different values of lambda .

So far we’ve been thinking of lambda as fixed and known and the function told us the probability of getting different values of x . But in real-life, we observe x and it is lambda that is unknown. The likelihood is the probability function seen through this lens: we want to find the lambda that makes the observed x the most likely. That is, given x , what value of lambda gives us the highest value of lprob_poisson ()?

In statistics, we highlight this change in perspective by writing \(f_{\mathbf{x}}(\lambda)\) instead of \(f(\lambda, \mathbf{x})\) . In R, we can use a function factory. We provide x and generate a function with a single parameter, lambda :

(We don’t need force() because length() implicitly forces evaluation of x .)

One nice thing about this approach is that we can do some precomputation: any term that only involves x can be computed once in the factory. This is useful because we’re going to need to call this function many times to find the best lambda .

Now we can use this function to find the value of lambda that maximizes the (log) likelihood:

Rather than trial and error, we can automate the process of finding the best value with optimise() . It will evaluate ll1() many times, using mathematical tricks to narrow in on the largest value as quickly as possible. The results tell us that the highest value is -30.27 which occurs when lambda = 32.1 :

Now, we could have solved this problem without using a function factory because optimise() passes ... on to the function being optimised. That means we could use the log-probability function directly:

The advantage of using a function factory here is fairly small, but there are two niceties:

We can precompute some values in the factory, saving computation time in each iteration.

The two-level design better reflects the mathematical structure of the underlying problem.

These advantages get bigger in more complex MLE problems, where you have multiple parameters and multiple data vectors.

10.4.4 Exercises

In boot_model() , why don’t I need to force the evaluation of df or model ?

Why might you formulate the Box-Cox transformation like this?

Why don’t you need to worry that boot_permute() stores a copy of the data inside the function that it generates?

How much time does ll_poisson2() save compared to ll_poisson1() ? Use bench::mark() to see how much faster the optimisation occurs. How does changing the length of x change the results?

10.5 Function factories + functionals

To finish off the chapter, I’ll show how you might combine functionals and function factories to turn data into many functions. The following code creates many specially named power functions by iterating over a list of arguments:

This idea extends in a straightforward way if your function factory takes two (replace map() with map2() ) or more (replace with pmap() ) arguments.

One downside of the current construction is that you have to prefix every function call with funs$ . There are three ways to eliminate this additional syntax:

For a very temporary effect, you can use with() :

I recommend this because it makes it very clear when code is being executed in a special context and what that context is.

For a longer effect, you can attach() the functions to the search path, then detach() when you’re done:

You’ve probably been told to avoid using attach() , and that’s generally good advice. However, the situation is a little different to the usual because we’re attaching a list of functions, not a data frame. It’s less likely that you’ll modify a function than a column in a data frame, so the some of the worst problems with attach() don’t apply.

Finally, you could copy the functions to the global environment with env_bind() (you’ll learn about !!! in Section 19.6 ). This is mostly permanent:

You can later unbind those same names, but there’s no guarantee that they haven’t been rebound in the meantime, and you might be deleting an object that someone else created.

You’ll learn an alternative approach to the same problem in Section 19.7.4 . Instead of using a function factory, you could construct the function with quasiquotation. This requires additional knowledge, but generates functions with readable bodies, and avoids accidentally capturing large objects in the enclosing scope. We use that idea in Section 21.2.4 when we work on tools for generating HTML from R.

10.5.1 Exercises

Which of the following commands is equivalent to with(x, f(z)) ?

  • It depends.

Compare and contrast the effects of env_bind() vs.  attach() for the following code.

Assignment Operators

Description.

Assign a value to a name.

There are three different assignment operators: two of them have leftwards and rightwards forms.

The operators <- and = assign into the environment in which they are evaluated. The operator <- can be used anywhere, whereas the operator = is only allowed at the top level (e.g., in the complete expression typed at the command prompt) or as one of the subexpressions in a braced list of expressions.

The operators <<- and ->> are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment. Note that their semantics differ from that in the S language, but are useful in conjunction with the scoping rules of R . See ‘The R Language Definition’ manual for further details and examples.

In all the assignment operator expressions, x can be a name or an expression defining a part of an object to be replaced (e.g., z[[1]] ). A syntactic name does not need to be quoted, though it can be (preferably by backtick s).

The leftwards forms of assignment <- = <<- group right to left, the other from left to right.

value . Thus one can use a <- b <- c <- 6 .

Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) The New S Language . Wadsworth & Brooks/Cole.

Chambers, J. M. (1998) Programming with Data. A Guide to the S Language . Springer (for = ).

assign (and its inverse get ), for “subassignment” such as x[i] <- v , see [<- ; further, environment .

assignOps: Assignment Operators

Assignment operators, description.

Assign a value to a name.

There are three different assignment operators: two of them have leftwards and rightwards forms.

The operators <- and = assign into the environment in which they are evaluated. The operator <- can be used anywhere, whereas the operator = is only allowed at the top level (e.g., in the complete expression typed at the command prompt) or as one of the subexpressions in a braced list of expressions.

The operators <<- and ->> are normally only used in functions, and cause a search to be made through parent environments for an existing definition of the variable being assigned. If such a variable is found (and its binding is not locked) then its value is redefined, otherwise assignment takes place in the global environment. Note that their semantics differ from that in the S language, but are useful in conjunction with the scoping rules of R . See ‘The R Language Definition’ manual for further details and examples.

In all the assignment operator expressions, x can be a name or an expression defining a part of an object to be replaced (e.g., z[[1]] ). A syntactic name does not need to be quoted, though it can be (preferably by backticks).

The leftwards forms of assignment <- = <<- group right to left, the other from left to right.

value . Thus one can use a <- b <- c <- 6 .

Becker, R. A., Chambers, J. M. and Wilks, A. R. (1988) The New S Language . Wadsworth & Brooks/Cole.

Chambers, J. M. (1998) Programming with Data. A Guide to the S Language . Springer (for = ).

assign (and its inverse get ), for “subassignment” such as x[i] <- v , see [<- ; further, environment .

R Package Documentation

Browse r packages, we want your feedback.

r super assignment operator

Add the following code to your website.

REMOVE THIS Copy to clipboard

For more information on customizing the embed code, read Embedding Snippets .

Introduction to R

Assignment operators.

You can assign values or functions to R objects using <- operator.

Multiple assignment operators

Description.

Assign values to name(s).

%<-% and %->% invisibly return value .

These operators are used primarily for their assignment side-effect. %<-% and %->% assign into the environment in which they are evaluated.

Name Structure

At its simplest, the name structure may be a single variable name, in which case %<-% and %->% perform regular assignment, x %<-% list(1, 2, 3) or list(1, 2, 3) %->% x .

To specify multiple variable names use a call to c() , for example c(x, y, z) %<-% c(1, 2, 3) .

When value is neither an atomic vector nor a list, %<-% and %->% will try to destructure value into a list before assigning variables, see destructure() .

object parts

Like assigning a variable, one may also assign part of an object, c(x, x[[1]]) %<-% list(list(), 1) .

nested names

One can also nest calls to c() when needed, c(x, c(y, z)) . This nested structure is used to unpack nested values, c(x, c(y, z)) %<-% list(1, list(2, 3)) .

collector variables

To gather extra values from the beginning, middle, or end of value use a collector variable. Collector variables are indicated with a ... prefix, c(...start, z) %<-% list(1, 2, 3, 4) .

skipping values

Use . in place of a variable name to skip a value without raising an error or assigning the value, c(x, ., z) %<-% list(1, 2, 3) .

Use ... to skip multiple values without raising an error or assigning the values, c(w, ..., z) %<-% list(1, NA, NA, 4) .

default values

Use = to specify a default value for a variable, c(x, y = NULL) %<-% tail(1, 2) .

When assigning part of an object a default value may not be specified because of the syntax enforced by R . The following would raise an "unexpected '=' ..." error, c(x, x[[1]] = 1) %<-% list(list()) .

For more on unpacking custom objects please refer to destructure() .

Blog of Ken W. Alger

Just another Tech Blog

Blog of Ken W. Alger

Assignment Operators in R – Which One to Use and Where

r super assignment operator

Assignment Operators

R has five common assignment operators:

Many style guides and traditionalists prefer the left arrow operator, <- . Why use that when it’s an extra keystroke?  <- always means assignment. The equal sign is overloaded a bit taking on the roles of an assignment operator, function argument binding, or depending on the context, case statement.

Equal or “arrow” as an Assignment Operator?

In R, both the equal and arrow symbols work to assign values. Therefore, the following statements have the same effect of assigning a value on the right to the variable on the left:

There is also a right arrow, -> which assigns the value on the left, to a variable on the right:

All three assign the  value of forty-two to the  variable   x .

So what’s the difference? Are these assignment operators interchangeable? Mostly, yes. The difference comes into play, however, when working with functions.

The equal sign can also work as an operator for function parameters.

x <- 42 y <- 18 function(value = x-y)

History of the <- Operator

r super assignment operator

The S language also didn’t have == for equality testing, so that was left to the single equal sign. Therefore, variable assignment needed to be accomplished with a different symbol, and the arrow was chosen.

There are some differences of opinion as to which assignment operator to use when it comes to = vs <-. Some believe that = is more clear. The <- operator maintains backward compatibility with S.  Google’s R Style Guide recommends using the <- assignment operator, which seems to be a pretty decent reason as well. When all is said and done, though, it is like many things in programming, it depends on what your team does.

r super assignment operator

Share this:

  • Click to share on Twitter (Opens in new window)
  • Click to share on LinkedIn (Opens in new window)
  • Click to email a link to a friend (Opens in new window)
  • Click to print (Opens in new window)

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Notify me of follow-up comments by email.

Notify me of new posts by email.

This site uses Akismet to reduce spam. Learn how your comment data is processed .

Popular Tutorials

Popular examples, learn python interactively, r introduction.

  • R Reserved Words
  • R Variables and Constants

R Operators

  • R Operator Precedence and Associativitys

R Flow Control

  • R if…else Statement

R ifelse() Function

  • R while Loop
  • R break and next Statement
  • R repeat loop
  • R Functions
  • R Return Value from Function
  • R Environment and Scope
  • R Recursive Function

R Infix Operator

  • R switch() Function

R Data Structures

  • R Data Frame

R Object & Class

  • R Classes and Objects
  • R Reference Class

R Graphs & Charts

  • R Histograms
  • R Pie Chart
  • R Strip Chart

R Advanced Topics

  • R Plot Function
  • R Multiple Plots
  • Saving a Plot in R
  • R Plot Color

Related Topics

R Operator Precedence and Associativity

R Program to Add Two Vectors

In this article, you will learn about different R operators with the help of examples.

R has many operators to carry out different mathematical and logical operations. Operators perform tasks including arithmetic, logical and bitwise operations.

  • Type of operators in R

Operators in R can mainly be classified into the following categories:

  • Arithmetic Operators
  • Relational Operators
  • Logical Operators
  • Assignment Operators
  • R Arithmetic Operators

These operators are used to carry out mathematical operations like addition and multiplication. Here is a list of arithmetic operators available in R.

Let's look at an example illustrating the use of the above operators:

  • R Relational Operators

Relational operators are used to compare between values. Here is a list of relational operators available in R.

Let's see an example for this:

  • Operation on Vectors

The above mentioned operators work on vectors . The variables used above were in fact single element vectors.

We can use the function c() (as in concatenate) to make vectors in R.

All operations are carried out in element-wise fashion. Here is an example.

When there is a mismatch in length (number of elements) of operand vectors, the elements in the shorter one are recycled in a cyclic manner to match the length of the longer one.

R will issue a warning if the length of the longer vector is not an integral multiple of the shorter vector.

  • R Logical Operators

Logical operators are used to carry out Boolean operations like AND , OR etc.

Operators & and | perform element-wise operation producing result having length of the longer operand.

But && and || examines only the first element of the operands resulting in a single length logical vector.

Zero is considered FALSE and non-zero numbers are taken as TRUE . Let's see an example for this:

  • R Assignment Operators

These operators are used to assign values to variables.

The operators <- and = can be used, almost interchangeably, to assign to variables in the same environment.

The <<- operator is used for assigning to variables in the parent environments (more like global assignments). The rightward assignments, although available, are rarely used.

Check out these examples to learn more:

  • Add Two Vectors
  • Take Input From User
  • R Multiplication Table

Table of Contents

  • Introduction

Sorry about that.

R Tutorials

Programming

Assignment Operators in R

R provides two operators for assignment: <- and = .

Understanding their proper use is crucial for writing clear and readable R code.

Using the <- Operator

For assignments.

The <- operator is the preferred choice for assigning values to variables in R.

It clearly distinguishes assignment from argument specification in function calls.

Readability and Tradition

  • This usage aligns with R’s tradition and enhances code readability.

Using the = Operator

The = operator is commonly used to explicitly specify named arguments in function calls.

It helps in distinguishing argument assignment from variable assignment.

Assignment Capability

  • While = can also be used for assignment, this practice is less common and not recommended for clarity.

Mixing Up Operators

Potential confusion.

Using = for general assignments can lead to confusion, especially when reading or debugging code.

Mixing operators inconsistently can obscure the distinction between assignment and function argument specification.

  • In the example above, x = 10 might be mistaken for a function argument rather than an assignment.

Best Practices Recap

Consistency and clarity.

Use <- for variable assignments to maintain consistency and clarity.

Reserve = for specifying named arguments in function calls.

Avoiding Common Mistakes

Be mindful of the context in which you use each operator to prevent misunderstandings.

Consistently using the operators as recommended helps make your code more readable and maintainable.

Quiz: Assignment Operator Best Practices

Which of the following examples demonstrates the recommended use of assignment operators in R?

  • my_var = 5; mean(x = my_var)
  • my_var <- 5; mean(x <- my_var)
  • my_var <- 5; mean(x = my_var)
  • my_var = 5; mean(x <- my_var)
  • The correct answer is 3 . my_var <- 5; mean(x = my_var) correctly uses <- for variable assignment and = for specifying a named argument in a function call.

r super assignment operator

UC Business Analytics R Programming Guide

Assignment & evaluation.

The first operator you’ll run into is the assignment operator. The assignment operator is used to assign a value. For instance we can assign the value 3 to the variable x using the <- assignment operator. We can then evaluate the variable by simply typing x at the command line which will return the value of x . Note that prior to the value returned you’ll see ## [1] in the command line. This simply implies that the output returned is the first output. Note that you can type any comments in your code by preceding the comment with the hashtag ( # ) symbol. Any values, symbols, and texts following # will not be evaluated.

Interestingly, R actually allows for five assignment operators:

The original assignment operator in R was <- and has continued to be the preferred among R users. The = assignment operator was added in 2001 primarily because it is the accepted assignment operator in many other languages and beginners to R coming from other languages were so prone to use it. However, R uses = to associate function arguments with values (i.e. f(x = 3) explicitly means to call function f and set the argument x to 3. Consequently, most R programmers prefer to keep = reserved for argument association and use <- for assignment.

The operators <<- is normally only used in functions which we will not get into the details. And the rightward assignment operators perform the same as their leftward counterparts, they just assign the value in an opposite direction.

Overwhelmed yet? Don’t be. This is just meant to show you that there are options and you will likely come across them sooner or later. My suggestion is to stick with the tried and true <- operator. This is the most conventional assignment operator used and is what you will find in all the base R source code…which means it should be good enough for you.

Lastly, note that R is a case sensitive programming language. Meaning all variables, functions, and objects must be called by their exact spelling:

R-bloggers

R news and tutorials contributed by hundreds of R bloggers

6 life-altering rstudio keyboard shortcuts.

Posted on January 4, 2021 by Business Science in R bloggers | 0 Comments

[social4i size="small" align="align-left"] --> [This article was first published on business-science.io , and kindly contributed to R-bloggers ]. (You can report issue about the content on this page here ) Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

This article is part of a R-Tips Weekly, a weekly video tutorial that shows you step-by-step how to do common R coding tasks.

The RStudio IDE is amazing. You can enhance your R productivity even more with these simple keyboard shortcuts.

Here are the links to get set up. ?

  • Get the Code
  • YouTube Tutorial

6 Keyboard Shortcuts (that will change your life)

Let’s speed up common activities with these 6 super-useful keyboard shortcuts.

r super assignment operator

1: Commenting & Uncommenting Code [Ctrl + Shift + C]

I use this all the time to turn text into commented text. Works with multiple lines too.

Go from this…

r super assignment operator

To this…

r super assignment operator

2: Add the Pipe %>% [Ctrl + Shift + M]

My students absolutely love this. You can easily add the Pipe %>% in any spot you’d like! Perfect for data wrangling with dplyr.

r super assignment operator

3: Insert The Assignment Operator [Alt + -]

My code has tons of assignment operators. This is a simple, time-saver that will make you more productive in building functions and assigning variables values.

r super assignment operator

4: Cursor-Select Multiple Lines [Ctrl + Alt + Up/Down/Click]

This is a recent addition to my portfolio of must-know keyboard shortcuts. Using Multi-Cursor Select has now become a go-to for editing R code .

Multi-Line Select

r super assignment operator

…And edit!

r super assignment operator

5: Find in Files [Ctrl + Shift + F]

THIS IS A SUPER POWER. Seriously. Learn to use this one right now!

Find in Files

r super assignment operator

Found every instance of ggplot by file!

r super assignment operator

6: Keyboard Shortcut Cheat Sheet [Alt + Shift + K]

More shortcuts!!! Run this to get a Keyboard Shortcut Cheat Sheet.

r super assignment operator

Your coworkers will be jealous of your productivity. ?

But if you really want to improve your productivity…

Here’s how to master R. ?

What happens after you learn R for Business.

The look on your boss’s face after you’ve launched your first Shiny App . ?

This is career acceleration.

SETUP R-TIPS WEEKLY PROJECT

Sign Up to Get the R-Tips Weekly (You’ll get email notifications of NEW R-Tips as they are released): https://mailchi.mp/business-science/r-tips-newsletter

Set Up the GitHub Repo: https://github.com/business-science/free_r_tips

Check out the setup video (https://youtu.be/F7aYV0RPyD0). Or, Hit Pull in the Git Menu to get the R-Tips Code

Once you take these actions, you’ll be set up to receive R-Tips with Code every week. =)

  • Interactive Principal Component Analysis in R
  • How to Forecast with ARIMA Models in R
  • Automate Excel in R
  • Detect Relationships with Linear Regression

To leave a comment for the author, please follow the link and comment on their blog: business-science.io . R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job . Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Copyright © 2022 | MH Corporate basic by MH Themes

Never miss an update! Subscribe to R-bloggers to receive e-mails with the latest R posts. (You will not see this message again.)

IMAGES

  1. R Operators

    r super assignment operator

  2. R Operators

    r super assignment operator

  3. Assignment Operators in R (3 Examples)

    r super assignment operator

  4. R Operators

    r super assignment operator

  5. R

    r super assignment operator

  6. [Solved] R assignment operator ("

    r super assignment operator

VIDEO

  1. Section 3 Operators Part 1 UNIT-4: INTRODUCTION TO DYNAMIC WEBSITES USING JAVASCRIPT 803

  2. Assignment Operator and conditional operator #trending #education #coding #java

  3. Oxygen and Helium (School project)

COMMENTS

  1. How do you use "<<-" (scoping assignment) in R?

    This makes it possible to maintain a counter that records how many times a function has been called, as the following example shows. Each time new_counter is run, it creates an environment, initialises the counter i in this environment, and then creates a new function. new_counter <- function() {. i <- 0.

  2. Assignment Operators in R (3 Examples)

    On this page you'll learn how to apply the different assignment operators in the R programming language. The content of the article is structured as follows: 1) Example 1: Why You Should Use <- Instead of = in R. 2) Example 2: When <- is Really Different Compared to =. 3) Example 3: The Difference Between <- and <<-. 4) Video ...

  3. 7 Environments

    7.1 Introduction. The environment is the data structure that powers scoping. This chapter dives deep into environments, describing their structure in depth, and using them to improve your understanding of the four scoping rules described in Section 6.4 . Understanding environments is not necessary for day-to-day use of R.

  4. [R] What does the "<<-" operator mean?

    It's the 'superassignment' operator. It does the assignment in the. enclosing environment. That is, starting with the enclosing frame, it. variable called ecov_xy, and then assigns to it. If it never finds. an existing ecov_xy it creates one in the global environment. that modify the state by using superassignment. a<-0.

  5. 14 Functional Programming in R

    The super-assignment operator looks for the name heavenly_hash in the parent environment of the run-time environment, If if finds heavenly_hash there then it changes its value to 5 and stops. Otherwise it looks in the next parent up, and so on until it reaches the Global Environment, at which point if it doesn't find a heavenly_hash it ...

  6. Scoping in R

    Variable assignment. <-is the variable assignment operator in R. The expression x <- 1 assigns the value 1 to the variable x in the current environment. If a mapping for x already exists in the environment, then the assignment will update and overwrite the existing value. Otherwise, a new mapping is created in the environment.

  7. 10 Function factories

    The super assignment operator, <<-rebinds an existing name found in a parent environment. The following example shows how we can combine these ideas to create a function that records how many times it has been called: new_counter <-function {i <-0 function {i <<-i + 1 i}} counter_one <-new_counter counter_two <-new_counter

  8. R: Assignment Operators

    Details. There are three different assignment operators: two of them have leftwards and rightwards forms. The operators <-and = assign into the environment in which they are evaluated. The operator <-can be used anywhere, whereas the operator = is only allowed at the top level (e.g., in the complete expression typed at the command prompt) or as one of the subexpressions in a braced list of ...

  9. What is `<<-` in R?

    3 Answers. a <<- 2. That is the replacement occurs in the nearest enclosing environment that contains an object of the same name, or the workspace (that is the example case) if none do. It almost means global assignment (see whuber's comment, and the linked docs on scoping). So if you assign A the value of 2 using A <<- 2 within, for example, a ...

  10. r

    The operators <- and = assign into the environment in which they are evaluated. The operator <- can be used anywhere, whereas the operator = is only allowed at the top level (e.g., in the complete expression typed at the command prompt) or as one of the subexpressions in a braced list of expressions. Share.

  11. assignOps: Assignment Operators

    There are three different assignment operators: two of them have leftwards and rightwards forms. The operators <- and = assign into the environment in which they are evaluated. The operator <- can be used anywhere, whereas the operator = is only allowed at the top level (e.g., in the complete expression typed at the command prompt) or as one of ...

  12. Assignment operators

    Assignment operators. You can assign values or functions to R objects using <- operator. x <- 3 # assign 3 to 'x' x.

  13. R: Multiple assignment operators

    the basics. At its simplest, the name structure may be a single variable name, in which case %<-% and %->% perform regular assignment, x %<-% list (1, 2, 3) or list (1, 2, 3) %->% x . To specify multiple variable names use a call to c (), for example c (x, y, z) %<-% c (1, 2, 3) . When value is neither an atomic vector nor a list, %<-% and ...

  14. Assignment Operators in R

    In R, both the equal and arrow symbols work to assign values. Therefore, the following statements have the same effect of assigning a value on the right to the variable on the left: x = 42. x <- 42. There is also a right arrow, -> which assigns the value on the left, to a variable on the right: 42 -> x. All three assign the value of forty-two ...

  15. What is the difference between assign () and <<- in R?

    According to the manual page here, . The operators <<-and ->> cause a search to made through the environment for an existing definition of the variable being assigned.. I've never had to do this in practice, but to my mind, assign wins a lot of points for specifying the environment exactly, without even having to think about R's scoping rules. The <<-performs a search through environments and ...

  16. R Operators (With Examples)

    The above mentioned operators work on vectors. The variables used above were in fact single element vectors. We can use the function c () (as in concatenate) to make vectors in R. All operations are carried out in element-wise fashion. Here is an example. x <- c(2, 8, 3) y <- c(6, 4, 1) x + y. x > y.

  17. Assignment Operators in R

    This usage aligns with R's tradition and enhances code readability. Using the = Operator. The = operator is commonly used to explicitly specify named arguments in function calls. It helps in distinguishing argument assignment from variable assignment. # Correct usage of = for specifying function arguments plot(x = 1:10, y = rnorm(10), type ...

  18. Assignment & Evaluation · UC Business Analytics R Programming Guide

    The original assignment operator in R was <-and has continued to be the preferred among R users. The = assignment operator was added in 2001 primarily because it is the accepted assignment operator in many other languages and beginners to R coming from other languages were so prone to use it. However, R uses = to associate function arguments with values (i.e. f(x = 3) explicitly means to call ...

  19. Assignment operators in R: '<-' and '<<-'

    1 Answer. Sorted by: 7. <- assigns an object to the environment in which it is evaluated (local scope). <<- assigns an object to the next highest environment that the name is found in or the global namespace if no name is found. See the documentation here.

  20. 6 Life-Altering RStudio Keyboard Shortcuts

    Let's speed up common activities with these 6 super-useful keyboard shortcuts. (Click image to play tutorial) 1: Commenting & Uncommenting Code ... My code has tons of assignment operators. This is a simple, time-saver that will make you more productive in building functions and assigning variables values. 4: Cursor-Select Multiple Lines ...

  21. Behavior of assignment operators ('=' and '<-') inside a function in R

    This is related to Assignment operators in R: '=' and '<-'; however, my question is not answered there.. The linked question and answers explain that using <-inside of a function declares the variable assignment in the user workspace, so that the variable can be used after the function is called. (Ed note: that is not actually stated in the linked answer, and if it were stated, it would be wrong.