web-dev-qa-db-ja.com

遅延評価の癖を説明する

特にGithubに関するHadleyWickhamsの本を読んでいます 遅延評価に関するこの部分 。そこで彼は、add/adders関数を使用して、遅延評価の結果の例を示します。そのビットを引用させてください:

この[遅延評価]は、ラップまたはループでクロージャを作成するときに重要です。

add <- function(x) {
  function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
adders[[10]](10)

xは、加算関数の1つを最初に呼び出したときに遅延評価されます。この時点で、ループは完了し、xの最終値は10です。したがって、すべての加算関数は入力に10を加算しますが、おそらくあなたが望んでいたものではありません。手動で評価を強制すると、問題が修正されます。

add <- function(x) {
  force(x)
  function(y) x + y
}
adders2 <- lapply(1:10, add)
adders2[[1]](10)
adders2[[10]](10)

私はそのビットを理解していないようで、そこにある説明は最小限です。誰かがその特定の例を詳しく説明し、そこで何が起こっているのか説明してもらえますか? 「この時点で、ループは完了し、xの最終値は10です」という文に特に戸惑います。どのループ?最終的な価値はどこですか?私が見逃している単純なものに違いないが、私はそれを見ていない。よろしくお願いします。

61
Maxim.K

の目標:

adders <- lapply(1:10, function(x)  add(x) )

add関数のリストを作成することです。最初は入力に1を追加し、2番目は2を追加します。遅延評価により、Rは、実際に関数の呼び出しを開始するまで、実際に加算関数が作成されるのを待ちます。問題は、最初の加算関数を作成した後、xlapplyループによって増加し、値10で終了することです。最初の加算関数を呼び出すと、遅延評価によって関数が作成されるようになりました。 、xの値を取得します。問題は、元のxが1に等しくなく、lapplyループの最後の値(つまり10)に等しくなることです。

したがって、遅延評価により、すべての加算関数は、関数の実際の構築でlapplyループが完了するまで待機します。次に、同じ値、つまり10で関数を作成します。Hadleyが提案する解決策は、xを直接評価し、遅延評価を回避し、正しいx値で正しい関数を取得することです。 。

35
Paul Hiemstra

これは、R3.2.0以降では当てはまりません。

変更ログ の対応する行は次のようになります。

Apply関数やReduce()などの高階関数は、遅延評価とクロージャ内の変数キャプチャの間の望ましくない相互作用を排除するために、適用する関数に引数を強制するようになりました。

本当に:

add <- function(x) {
  function(y) x + y
}
adders <- lapply(1:10, add)
adders[[1]](10)
# [1] 11
adders[[10]](10)
# [1] 20
57
jhin