関数内の <- による代入はグローバル変数を変更しない
関数の中で<-を使って外側と同じ名前の変数に代入しても、それは関数内だけのローカル変数を新しく作るだけで、外側のグローバル変数には影響しません。外側の変数を書き換えたい場合は<<-を使う必要があります。
なぜエラーが出ないのか
出力: 0
(エラーなし)- Rは何も報告しません。文法としても実行としても正しいコードだからです
0- 実際の出力 — 期待した結果と食い違っている箇所
このエラーが出る典型パターン
パターン1
1 counter <- 0 2 increment <- function() { 3 counter <- counter + 1 ^ 4 } 5 increment() 6 increment() 7 cat(counter, "\n")
関数内の<-はローカルなcounterを新しく作るだけで、外側のcounterは変わりません。<<-を使うと外側の変数が更新されます。
直し方: <- を <<- にします。
パターン2
1 total <- 0 2 add_amount <- function(x) { 3 total <- total + x ^ 4 } 5 add_amount(5) 6 cat(total, "\n")
add_amount内の<-はローカルのtotalに代入するだけで、呼び出し元のtotalには反映されません。
直し方: <- を <<- にします。
パターン3
1 balance <- 100 2 deposit <- function(amount) { 3 balance <- balance + amount ^ 4 } 5 deposit(50) 6 cat(balance, "\n")
depositを呼んでも外側のbalanceが増えないのは、関数内の代入がローカルスコープに閉じているためです。
直し方: <- を <<- にします。
パターン4
1 score <- 0 2 add_point <- function() { 3 score <- score + 1 ^ 4 } 5 add_point() 6 add_point() 7 add_point() 8 cat(score, "\n")
add_pointを3回呼んでもscoreが増えないのは、関数の中の代入が毎回ローカルなscoreを作り直しているからです。
直し方: <- を <<- にします。
パターン5
1 count <- 0 2 tally <- function() { 3 count <- count + 1 ^ 4 } 5 tally() 6 tally() 7 tally() 8 tally() 9 cat(count, "\n")
外側のcountを実際に書き換えたい場合は、関数内で<<-を使って明示的にグローバル環境を指定する必要があります。
直し方: <- を <<- にします。
よくある誤解
「関数の中で同じ名前に代入すれば、外側の変数もそのまま更新されるはず」という思い込みは誤りです。<-は常にその関数のローカルスコープに新しい束縛を作るため、外側の変数を変更するには<<-による明示的な操作が必要です。
実務での勘所
<<-は単純に「1つ外側のスコープに代入する」わけではありません。現在の関数の外側の環境を、その名前の既存の束縛が見つかるまで次々と辿っていき、最初に見つかった場所を書き換えます。グローバル環境まで遡っても該当する名前が見つからなければ、エラーにはならずグローバル環境に新しい変数を作成します。この「見つかるまで探し続け、無ければグローバルに作る」という挙動は意図せぬ場所の変数を書き換える原因になりうるため、<<-を使う際は対象の変数がどの環境にあるかを意識する必要があります。