Escopo e avaliação de funções em R

8

Dada a seguinte função

f <- function(x) {
    g <- function(y) {
            y + z
    }
    z <- 4
    x + g(x)
 }

Se alguém executa o seguinte código em R, por que a resposta é 10? Estou um pouco confuso sobre como y se encaixa nessa questão.

z <- 10
f(3)
nzhanggh
fonte
2
Ele está recebendo o 'z' de dentro da função env
akrun
5
A função não está apenas funcionando 4 + 2*xno final? Onde 4 = z
markus
1
@markus Sim, mas a pergunta é: por que z = 4? Pode ser razoável esperar que a definição da função capture z = 10.
Robert Dodier
@RobertDodier Verifica as variáveis ​​dentro do primeiro env, ou seja, dentro da função, encontra-o e para de procurar outro local, ou seja, no env pai. Você pode testar renomeando o 'z' dentro da função, ou seja, z1 <- 4dentro da função ef(3)# [1] 16
akrun 12/03
Ou especifique o ambiente, ou seja, z <- 4; environment(g) <- .GlobalEnve depois chamez <- 10 > f(3) [1] 16
akrun

Respostas:

9

R usa o escopo lexical, o que significa que, se um objeto é referenciado, mas não definido em uma função, ele é procurado no ambiente em que a função está definida , não no ambiente do qual foi chamado.

z é referenciado em g, mas não é definido em g; portanto, ele olha para o ambiente em que g está definido e esse é o ambiente em f; portanto, g usa z = 4.

Na verdade, nesse caso, o ambiente em que g é definido é o mesmo que o ambiente em que g é chamado; portanto, de qualquer maneira que você o veja, z = 4 deve ser usado. Se as funções padronizadas no ambiente global para procurar objetos não definidos na função, ele usaria z = 10, mas não é assim que R funciona.

Fazendo funcionar de maneira diferente

Se, por algum motivo, você quiser forçar g a procurar z no ambiente em que f é chamado, você poderá fazer isso (onde parent.frame()se refere ao ambiente a partir do qual f é chamado).

f2 <- function(x, envir = parent.frame()) {
    g <- function(y) {
            y + with(envir, z)
    }
    z <- 4
    x + g(x)
 }
 z <- 10
 f2(3)
 ## [1] 16

ou poderíamos usar, y + envir$zexceto que isso pareceria apenas no quadro pai e não em seus ancestrais, ao passo withque procurará nos ancestrais do quadro pai, se não encontrado no quadro pai.

Uma alternativa é alterar o ambiente de g dessa maneira, para procurar envirobjetos não encontrados em g:

f3 <- function(x, envir = parent.frame()) {
    g <- function(y) {
            y + z
    }
    environment(g) <- envir
    z <- 4
    x + g(x)
 }
 z <- 10
 f3(3)
 ## [1] 16
G. Grothendieck
fonte