Rは意外と普通の言語だったのでちょっとガッカリしてたけれど、ちょっと変態っぽいところを見つけた!
Coursera の Computing for Data Analysis の Week 2 の Scoping Rules で「Note that R has separate namespaces for functions and non-functions so it’s possible to have an object named c and a function named c.」と書いてあって、Lisp-2的な意味かと思ったのだけれど、でも、以下のように関数を代入後にそれ以外を代入しても上書きされているように見えるしなぁ……と不思議に思っていた。
> f <- function(x) { x + 1 }
> f
function(x) { x + 1 }
> f <- 1
> f
[1] 1
> f(2)
エラー: 関数 "f" を見つけることができませんでした
しかし、今日会社のRに詳しい人と話していて、以下のような非常に不可解な動作をすることが分かった。
> f <- function(x) { x + 1 }
> g <- function(x) { f <- 1; f(x) }
> g(2)
[1] 3
> h <- function(x) { f <- function(x) { x * 2 }; f(x) }
> h(2)
[1] 4
gの場合にはfに代入しているにも関わらず元の関数が呼ばれており、hの場合にはfに代入した新たな関数の方が呼ばれている。
一体どうやったらこうなるのかと考えてみて至った結論は、名前空間はひとつだけれど、関数呼び出しの関数部の名前を評価する際には、内側のスコープから順に見ていって、関数型でない場合にはさらに外側のスコープを見に行き、最初に見つかった関数型の値へと評価されるというもの。
ちゃんと言語仕様を確認したわけではないけれど、この仮説が正しいとしたら、すごいなぁ。面白い。変態的だけれど、実用上はなかなか便利かもしれない。
#compdata
そして、この論文読むと、Rは色々と面白いですね。