5.6 Scoping rules a uzávěry
Když R hledá hodnotu nějaké proměnné, prochází série různých prostředí (environment). Pokud např. zadáte výpis proměnné x
v konzoli, začíná R hledat x
nejdříve v globální prostředí (tj. základním pracovním prostředí R). Když ji tam nenajde, pokračuje do mateřského prostředí (parental environment) globálního prostředí, což je typicky poslední načtený balík. Pokud ji nenajde ani tam, pokračuje do dalšího mateřského prostředí atd. Pokud ji nikde nenajde, vypíše R chybu. Seznam prostředí, která R prohledává, vrací funkce search()
:
search()
## [1] ".GlobalEnv" "package:stats" "package:graphics"
## [4] "package:grDevices" "package:utils" "package:datasets"
## [7] "Autoloads" "package:base"
Pokud nic nezměníte, vyhledává se nejdříve v globálním prostředí a nakonec v balíku base. Když načtete nový balík, vloží se na druhé místo a posune všechny balíky směrem dolů.
Situace ve funkcích je zajímavější. R používá tzv. lexical scoping, což znamená, že vyhledávání začíná v prostředí, ve kterém byla funkce definovaná. Pokud je funkce zadefinovaná v globálním prostředí, vše funguje normálně. Pokud však funkce definovaná uvnitř jiné funkce, pak vyhledávání začíná v prostředí této funkce, a pak v prostředí vnější funkce. To slouží k tvorbě tzv. function factories.
n <- 17
make.power <- function(n) {
g <- function(x)
x ^ n
g
}
square <- make.power(2)
cube <- make.power(3)
square(2)
## [1] 4
cube(2)
## [1] 8
n
## [1] 17
Funkce make.power()
vrací funkci jedné proměnné. Tyto funkce však obsahují kromě formálního parametru x
také volný parametr n
. Když R hledá jeho hodnotu, začne nejdříve v prostředí, ve kterém byly funkce square()
a cube()
definovány. Tato prostředí jsou prostředí funkce make.power()
ve chvíli, kdy byla tato funkce spuštěna. Funkce square()
byla definována v prostředí, ve kterém bylo n = 2
, a toto prostředí si s sebou táhne. Stejně tak funkce cube()
si s sebou táhne prostředí, ve kterém je n = 3
. (Normálně volací prostředí funkce ve chvíli ukončení jejího běhu zaniká). Funkce square()
a cube()
jsou tzv. “uzávěry” (closures).
Existují situace, kdy je vytváření uzávěr užitečné. Jindy však uzávěry vzniknou, aniž byste si to výslovně přáli. To pak může být zdrojem překvapivých chyb.