Suppose you have a list L = [5, 6, 7] and you want to make a list with the squares of the numbers in it.
First, define the operation “square”: square(x) = x*x.
One way to do it — the way all of you have done it — is to start with an empty list and write a for loop that adds square(5) to the list, then square(6), then square(7).
Another way is to say: what I actually want to do is apply the function square to every element of this list. The general concept for doing this is called map:
map(square, L)
map is itself a function. It takes the function square and the list L and applies square to each of the elements. This is of course equivalent to writing a for loop, but that is the functional style:
In R, like in Python, you can enter literals. The simplest expressions are numerics and strings:
42## [1] 42
"Hello"## [1] "Hello"
R simply repeats these values back at us.
You can use R as a calculator:
42 + 43## [1] 85
(45 - 43) ** 3## [1] 8
You can evaluate logical values:
5 == (4 + 1)## [1] TRUE
7 > (5 - 1)## [1] TRUE
Note that to compare two values we use two equal signs ==. The resultant value is TRUE or FALSE (in R, you can also use T and F). It is a value, just like numeric values and character values are values; it is called a logical value.
The usual way to print is through cat. You can also use print; they are kind of the same.
cat(42 + 1)## 43
cat("Hello")## Hello
Note that Hello was printed without quotes — that’s because we are not printing the value of "Hello" back, we are just printing Hello.
You can print several values:
cat("Hello", 123, "hi", 5 + 1)## Hello 123 hi 6
The standard way of variable assignment in R is the arrow:
exam <- 80
cat(exam)## 80
You can also use =; it is almost the same. We will use the arrow. One nice thing about the arrow is that you can also use it the other way: 5 -> a works. Do not do that unless you know what you are doing — it is confusing, but you can do it.
Note how R variables are different from variables in math: in math you cannot say x = x + y (or rather, you can, but this will just mean that y = 0). In R, the expression exam <- exam + harvard.adj means: compute exam + harvard.adj, then store the resultant value back in the variable exam.
exam <- 80
harvard.adj <- 10
exam <- exam + harvard.adj
cat("Your exam grade is", exam)## Your exam grade is 90
if statements work like this. The parentheses around the condition are mandatory (unlike in Python). Braces are not mandatory if the body is a single expression — but you almost always use them anyway because they make multi-line bodies and else chains read better.
grade <- 98
if(grade >= 95){
cat("I'm reasonably happy")
}## I'm reasonably happy
# Single-expression form, no braces:
if(grade >= 95) cat("I'm reasonably happy")## I'm reasonably happy
else if and else work like this:
grade <- 88
if(grade >= 98){
cat("Hooray")
} else if(grade >= 95){
cat("OK")
} else {
cat("Alas")
}## Alas
One thing to watch out for when omitting braces: if you put else on its own line, the parser thinks the if is finished and gives a syntax error. So } else { always has to be on the same line, or you have to use braces around both arms.
A function works the usual way. For example, the absolute value:
my.abs <- function(x){
if(x >= 0){
x
} else{
-x
}
}
my.abs(-5)## [1] 5
This is the R style of writing a function. Notice that there is no return here.
Braces are not mandatory in function definitions either — if the body is a single expression, you can write the function on one line. These are all equivalent ways to define square:
square_a <- function(x){
x ** 2
}
square_b <- function(x) x ** 2 # no braces, body is one expression
square_c <- function(x) {return(x ** 2)} # explicit `return`
square_a(5); square_b(5); square_c(5)## [1] 25
## [1] 25
## [1] 25
The single-line form is idiomatic for short functions. What is going on is we are saying: the value of this expression is either x or -x depending on whether x >= 0 or not. The value of the expression — if you plug in x — is just whatever the appropriate branch evaluates to.
So you don’t think about it as “when I hit return, that’s what I return”. You think about it as substituting into a formula. In math, you are kind of familiar with this kind of thing:
\[f(x) = \begin{cases} x & \text{if } x \geq 0 \\ -x & \text{otherwise} \end{cases}\]
When you plug x in, this is what you get — it is not a return, it is substituting.
One way to think about this is that you are defining the function in the same way you would in any other programming language; the syntax is just the function name, then the arrow, then the word function, then the usual thing. Another way of thinking about it is that the right-hand side function(x){...} is itself an object — the function — and my.abs is just the variable that stores it.
This implies that you can define the function and just call it directly without ever assigning it to a name:
(function(x){
if(x >= 0){
x
} else{
-x
}
})(-5)## [1] 5
This works the same way in Python: abs is really a variable; you can say abs = 10 and now abs is 10.
In R you can write return if you want to, but really the last thing that has a value — that’s the value of the function. One way to think about this is that local variables are just shorthand:
h <- function(x){
y <- 2 * x
y ** 2 - x
}
h(2)## [1] 14
Here we defined a local variable y to help with the computation. The process we use is: substitute x <- 2; evaluate and substitute y <- 2 * 2 (i.e. 4); the value the function computes is \(4^2 - 2 = 14\). The value of h(2) was evaluated to 14. Note that we cannot access y outside of the function h.
It is important to distinguish between printing and returning values. Consider these two functions:
emo.state <- function(score){
if(score >= 98){
"Hooray"
} else if(score >= 95){
"OK"
} else {
"Alas"
}
}
emo.state.2 <- function(score){
if(score >= 98){
cat("Hooray")
} else if(score >= 95){
cat("OK")
} else {
cat("Alas")
}
}The function emo.state computes a value; it does not print anything. For example, emo.state(99) evaluates to "Hooray":
a <- emo.state(99)
cat(a)## Hooray
On the other hand:
res <- emo.state.2(98)## Hooray
This already had the effect of printing an output to the screen. That’s because when R sees cat("Hooray"), it outputs Hooray. But the value that the function computes is NULL:
print(res)## NULL
Comments work with #:
# This is a comment.
x <- 5 # inline commentThe workflow that we use and suggest is to always open a folder in VS Code (File → Open Folder). To work in a new programming language, install the appropriate extension. For R, look up R and R Markdown in the extensions panel.
Files come in two flavours:
.R files — plain R scripts..Rmd (R Markdown) files — literate-programming format where code goes in code chunks and the rest of the file is text. Similar to Python notebooks. Inside an Rmd file, code chunks look like:
``` r
print("Hello")
```
```
## [1] "Hello"
```