0Pricing
R Academy · Lezione

Regole dello scoping lessicale

Comprenda come R trova le variabili cercando negli environment genitori.

Regole dello scoping lessicale è una lezione R Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento R Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso R Academy include 4 lezioni in totale.

Che cos'è lo scope lessicale

Lo scope lessicale significa che una funzione cerca le variabili nel punto in cui è stata definita, non nel punto in cui viene chiamata. R utilizza lo scope lessicale. Questo comportamento è prevedibile: l'ambiente in cui una funzione cerca le variabili viene fissato al momento della sua creazione, non della chiamata.

x <- 'global'
f <- function() {
  cat('x =', x, '\n')  # looks where f was defined (global)
}
local({
  x <- 'local to local block'
  f()  # still prints global x, not the local one
})

Scope lessicale e scope dinamico

Nello scope dinamico (utilizzato in alcuni altri linguaggi), una funzione troverebbe la variabile nell'ambiente del chiamante. R utilizza invece lo scope lessicale: prevale sempre l'ambiente esterno presente al momento della definizione. In questo modo le funzioni si comportano in modo coerente indipendentemente dal punto da cui vengono chiamate.

val <- 100
make_adder <- function(n) {
  # n is captured from the definition environment
  function(x) x + n
}
add10 <- make_adder(10)
add20 <- make_adder(20)
cat(add10(5), '\n')   # 15 — n=10 from definition
cat(add20(5), '\n')   # 25 — n=20 from definition

Variabili libere e closure

Una variabile all'interno di una funzione che non è un parametro né il risultato di un'assegnazione locale è una variabile libera. R la cerca nell'ambiente esterno. Una funzione che cattura variabili libere viene chiamata closure.

base_rate <- 0.05   # free variable captured by f
f <- function(principal, years) {
  principal * (1 + base_rate) ^ years
}
cat('5 yr return:', f(1000, 5), '\n')
# Even if we change base_rate later:
base_rate <- 0.08
cat('New rate return:', f(1000, 5), '\n')

Le closure catturano gli ambienti

Ogni volta che viene chiamata una funzione factory, la funzione restituita (la closure) cattura un'istantanea dell'ambiente esterno. Chiamate diverse producono closure con valori catturati diversi: questo è alla base delle function factory.

power_fn <- function(exp) {
  function(x) x ^ exp
}
square <- power_fn(2)
cube   <- power_fn(3)
cat('square(4) =', square(4), '\n')
cat('cube(3)   =', cube(3),   '\n')

L'operatore <<-

<<- (assegnazione con doppia freccia) cerca nella catena dei genitori un'associazione esistente e la modifica sul posto. Se non trova alcuna associazione, ne crea una nell'ambiente globale. È lo strumento per modificare, dall'interno di una funzione, una variabile appartenente a uno scope esterno.

count <- 0
increment <- function() {
  count <<- count + 1
}
increment()
increment()
increment()
cat('count:', count, '\n')

<<- con le closure

L'uso più idiomatico di <<- è all'interno di closure che devono aggiornare lo stato nel proprio ambiente esterno. In questo modo si creano funzioni con stato, cioè funzioni dotate di memoria persistente tra una chiamata e l'altra.

make_counter <- function() {
  n <- 0
  list(
    increment = function() n <<- n + 1,
    get       = function() n,
    reset     = function() n <<- 0
  )
}
ctr <- make_counter()
ctr$increment()
ctr$increment()
cat('Count:', ctr$get(), '\n')
ctr$reset()
cat('After reset:', ctr$get(), '\n')

Scope nelle funzioni annidate

Quando le funzioni sono annidate, la funzione interna può vedere le variabili definite nella funzione esterna. L'ambiente della funzione esterna diventa l'ambiente esterno della funzione interna, formando una catena.

outer <- function() {
  greeting <- 'Hello'
  inner <- function(name) {
    # greeting comes from outer's environment
    paste(greeting, name)
  }
  inner('World')
}
cat(outer(), '\n')

Ricerca nella catena degli scope

Quando R cerca una variabile, esamina gli ambienti in questo ordine: ambiente della funzione → ambiente esterno → ambiente esterno di quello esterno → ... → globale → search path → base → empty. Vince la prima corrispondenza.

x <- 'global'
f <- function() {
  x <- 'local to f'
  g <- function() {
    # g has no x, so looks in f's env
    cat('g sees x =', x, '\n')
  }
  g()
}
f()

environment() di una funzione

È possibile esaminare l'ambiente esterno di qualsiasi funzione con environment(f). È persino possibile impostarlo con environment(f) <- e, modificando il punto in cui la funzione cercherà le variabili libere: una tecnica potente, ma avanzata.

x <- 'global_x'
f <- function() x
cat('f sees:', f(), '\n')

# Change f's enclosing environment
my_env <- new.env(parent = emptyenv())
my_env$x <- 'env_x'
environment(f) <- my_env
cat('f now sees:', f(), '\n')

Closure pratica: memoization

Lo scope lessicale e <<- consentono la memoization: memorizzi nella cache dell'ambiente della closure i risultati costosi da calcolare. La cache è privata della closure e persiste tra le chiamate.

make_memoized_fib <- function() {
  cache <- c()
  function(n) {
    if (!is.null(cache[n])) return(cache[n])
    if (n <= 1) { cache[n] <<- n; return(n) }
    result <- Recall(n-1) + Recall(n-2)
    cache[n] <<- result
    result
  }
}
fib <- make_memoized_fib()
cat(sapply(0:8, fib), '\n')

Una trappola dello scope lessicale: le variabili dei cicli

Una trappola classica consiste nel creare closure all'interno di un ciclo. Tutte le closure catturano lo stesso ambiente, non un'istantanea del valore. Quando vengono chiamate, la variabile del ciclo contiene ormai il valore finale.

fns <- vector('list', 3)
for (i in 1:3) {
  local({
    captured_i <- i
    fns[[captured_i]] <<- function() captured_i
  })
}
cat(fns[[1]](), fns[[2]](), fns[[3]](), '\n')

Verifica rapida

Con lo scope lessicale di R, dove cerca una funzione una variabile libera, cioè non definita nella funzione stessa?

Scope lessicale: concetti chiave

Concetti chiave sullo scope lessicale:

  • R utilizza lo scope lessicale: le funzioni cercano le variabili nel punto in cui sono state definite
  • Una funzione cattura il proprio ambiente esterno come closure
  • Le variabili libere vengono risolte al momento della definizione, non della chiamata
  • <<- modifica un'associazione nella catena dei genitori (o nell'ambiente globale se non la trova)
  • Closure + <<- = funzioni con stato privato persistente
  • Trappola delle closure nei cicli: utilizzi local() per forzare un nuovo ambiente a ogni iterazione
make_multiplier <- function(factor) {
  function(x) x * factor
}
double <- make_multiplier(2)
triple <- make_multiplier(3)
cat('double(7):', double(7), '\n')
cat('triple(7):', triple(7), '\n')
cat('double env factor:', get('factor', envir = environment(double)), '\n')

Domande Frequenti

La lezione «Regole dello scoping lessicale» è gratuita?

Sì — il testo completo di «Regole dello scoping lessicale» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso R Academy, passa a CoddyKit PRO. Il corso R Academy include 4 lezioni in totale.

Cosa imparerò in «Regole dello scoping lessicale»?

Comprenda come R trova le variabili cercando negli environment genitori. Eserciti R Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare R Academy?

Non è richiesta alcuna esperienza precedente. R Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Regole dello scoping lessicale»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione R Academy?

Sì. Ogni lezione R Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Che cos'è un environment in R?
  2. Regole dello scoping lessicale
  3. Scope globale e locale
  4. Creazione e analisi degli environment
← Torna a R Academy