What does the <<-
operator in R mean, what are their differences from <-
, and under what circumstances can it be useful?
What does the <<-
operator in R mean, what are their differences from <-
, and under what circumstances can it be useful?
I'll explain with an example.
> objeto_fora_da_funcao <- 1
> f <- function() {
objeto_fora_da_funcao <- 10
return(objeto_fora_da_funcao)
}
Outputs
> f()
# [1] 10
> objeto_fora_da_funcao
# [1] 1
Now, let's change <-
by <<-
within function f
:
> objeto_fora_da_funcao <- 1
> f <- function() {
objeto_fora_da_funcao <<- 10
return(objeto_fora_da_funcao)
}
Notice the outputs now:
Outputs
> objeto_fora_da_funcao
# [1] 1
> f()
# [1] 10
> objeto_fora_da_funcao
# [1] 10
What is behind this is the way R saves objects in environments, which could be seen as sets of objects (numbers, vectors, data.frames, functions, etc.).
<<-
is generally useful inside functions, because the functions work with their own, temporary "environments". Despite the functions of accessing global objects, the <-
operator is programmed to create (or reset) objects within the environment of the respective function, only. And that's exactly why <<-
exists. It will search for objects with that given name in all environments from the most specific to the most comprehensive (known as "Global environment").
This is useful when you want a function to change global variables.
<<-
can be useful for changing variables within the function environment without changing global variables:
Generating a counter that accumulates the value of i
in the function environment (based on the workbook of Hadley):
contador <- function() {
i <- 0
function() {
i <<- i + 1
i
}
}
cont1 <- contador()
cont1()
[1] 1
cont1()
[1] 2
cont1()
[1] 3
cont2 <- contador()
cont2() # note que o contador de cont2 é separdo de cont1
[1] 1
cont1()
[1] 4
Implementing memoization with local
and <<-
in fibonacci sequence (adapted example from R Inferno) :
fibonacci <- local({
memo <- c(0, 1, rep(NA, 100))
f <- function(x) {
if(x == 0) return(0)
if(x < 0) return(NA)
if(x > length(memo))
stop("’x’ too big for implementation")
if(!is.na(memo[x])) return(memo[x])
ans <- f(x-2) + f(x-1)
memo[x] <<- ans
ans
}
})
fibonacci(10)
[1] 34
Generating a fibonacci sequence with replicate
and <<-
fibonacci <- function(n){
x0 <- 0
x1 <- 1
x <- numeric() # para assegurar que <<- não altere a variável global
fib <- function(){x <<- x1 + x0; x0 <<- x1; x1 <<- x}
c(x0, x1, replicate(n-2, fib()))
}
fibonacci(10)
[1] 0 1 1 2 3 5 8 13 21 34