Rでの関数のスコープと評価


8

次の関数を考える

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

Rで次のコードを実行すると、答えはなぜ10になりますか?yがこの質問にどのように対応するかについて少し混乱しています。

z <- 10
f(3)

2
関数env内から「z」を取得しています
akrun

5
4 + 2*x最後に、関数は単にやっているのではないですか?ここで、4 = z
マーカス

1
@markusはい、しかし問題は、なぜz = 4なのかということです。その関数定義キャプチャさz = 10を期待するのが妥当かもしれない
ロバートDodier

@RobertDodier最初のenv内、つまり関数内の変数をチェックし、それを見つけて、親env内の他の場所での検索を停止します。あなたはつまり、関数内で「Z」をリネームすることでテストすることができz1 <- 4、関数内およびf(3)# [1] 16
akrun

または、環境を指定してz <- 4; environment(g) <- .GlobalEnv電話をかけるz <- 10 > f(3) [1] 16
akrun

回答:


9

Rは字句スコープを使用します。つまり、オブジェクトが参照されているが関数で定義されていない場合、そのオブジェクトは、その関数が呼び出された環境ではなく、関数が定義されている環境で検索されます。

zはgで参照されていますが、gでは定義されていないため、gが定義されている環境、つまり、f内の環境を参照しているため、gはz = 4を使用します。

実際、この場合、gが定義されている環境は、gの呼び出し元の環境と同じであるため、z = 4を使用する必要があります。関数がデフォルトでグローバル環境に設定されていて、関数で定義されていないオブジェクトを探す場合、z = 10を使用しますが、Rの動作はそうではありません。

別の方法で機能させる

何らかの理由で、fが呼び出される環境でgにzを検索させたい場合は、これを実行できます(ここparent.frame()で、fが呼び出される環境を指します)。

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

または、それがy + envir$z親フレームでのみ見られ、そのwith祖先ではなく、親フレームで見つからない場合は親フレームの祖先を探すことを除いて、使用できます。

別の方法はenvir、gで見つからないオブジェクトを探すように、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.