2011-10-26 6 views
16

昨日は、例えば、静的関数と変数を作成することができますどのように(ローカル)ビルVenablesから学んだlocal()はRの他のアプローチとどのように違いますか?

コマンドプロンプトから次のように振る舞う
example <- local({ 
    hidden.x <- "You can't see me!" 
    hidden.fn <- function(){ 
    cat("\"hidden.fn()\"") 
    } 
    function(){ 
    cat("You can see and call example()\n") 
    cat("but you can't see hidden.x\n") 
    cat("and you can't call ") 
    hidden.fn() 
    cat("\n") 
    } 
}) 

:私はこれを見てきました

> ls() 
[1] "example" 
> example() 
You can see and call example() 
but you can't see hidden.x 
and you can't call "hidden.fn()" 
> hidden.x     
Error: object 'hidden.x' not found 
> hidden.fn() 
Error: could not find function "hidden.fn" 

異なるアプローチが採用されたStatic Variables in Rで議論されている種類のもの。

この2つの方法の長所と短所は何ですか?

答えて

12

カプセル化

プログラミングのこのスタイルの利点は、あなたが、彼らはあなたが何を考えて含まれていることをより確信することができるように隠されたオブジェクトはおそらく何か他のもので上書きされないことです。それらは容易にアクセスできないので、誤って使用されることはありません。リンク先のポストにはグローバル変数countがあり、どこからでもアクセスして上書きすることができるので、コードをデバッグしてcountを見て、その変更を見れば、コードのどの部分にそれを変更しました。対照的に、質問のサンプルコードでは、コードの他の部分が関与していないというより大きな保証があります。私たちは実際にはないことは容易ものの、隠された機能にアクセスすることができます

注:

# run hidden.fn 
environment(example)$hidden.fn() 

オブジェクト指向プログラミング

はまた、これは指向プログラミングexamplehidden.fnオブジェクトに非常に近いことに注意してくださいメソッドであり、hidden.xはプロパティです。私たちは、それを明示的にするために、このようにそれを行うことができます:

library(proto) 
p <- proto(x = "x", 
    fn = function(.) cat(' "fn()"\n '), 
    example = function(.) .$fn() 
) 
p$example() # prints "fn()" 

プロトは隠さないxfnが、そのあなたが本当にされていないそれらにアクセスするp$xp$fn()を使用する必要がありますので、誤ってそれらにアクセスすることは容易ではありません

オブジェクト指向のアプローチは、継承の可能性を追加し、例えば:e <- environment(example); e$hidden.fn()

EDITを書くことができることとは異なりますpの子を定義することができ、pのように動作します。ただし、fnを上書きします。

ch <- p$proto(fn = function(.) cat("Hello from ch\n")) # child 
ch$example() # prints: Hello from ch 
6

local()シングルトンパターンを実装することができる - 例えば、snowパッケージは、ユーザが作成する可能性があること単一RMPIインスタンスを追跡するためにこれを使用します。

getMPIcluster <- NULL 
setMPIcluster <- NULL 
local({ 
    cl <- NULL 
    getMPIcluster <<- function() cl 
    setMPIcluster <<- function(new) cl <<- new 
}) 

local()も句の最後の行の最後のオブジェクトを作成するために必要な大規模な中間オブジェクトを割り当てる、例えば、スクリプト内のメモリを管理するために使用されるかもしれません。大きな中間オブジェクトは、localが返されたときにガベージコレクションに使用できます。

ファンクションを使用してクロージャを作成するファクトリパターンは、open.accountが呼び出されるたびに新しいアカウントが作成される、Introduction To Rドキュメントのbank accountの例です。

@otsawは述べているように、メモ化は、クローラ

library(XML) 
crawler <- local({ 
    seen <- new.env(parent=emptyenv()) 
    .do_crawl <- function(url, base, pattern) { 
     if (!exists(url, seen)) { 
      message(url) 
      xml <- htmlTreeParse(url, useInternal=TRUE) 
      hrefs <- unlist(getNodeSet(xml, "//a/@href")) 
      urls <- 
       sprintf("%s%s", base, grep(pattern, hrefs, value=TRUE)) 
      seen[[url]] <- length(urls) 
      for (url in urls) 
       .do_crawl(url, base, pattern) 
     } 
    } 
    .do_report <- function(url) { 
     urls <- as.list(seen) 
     data.frame(Url=names(urls), Links=unlist(unname(urls)), 
        stringsAsFactors=FALSE) 
    } 
    list(crawl=function(base, pattern="^/.*html$") { 
     .do_crawl(base, base, pattern) 
    }, report=.do_report) 
}) 

crawler$crawl(favorite_url) 
dim(crawler$report()) 

のキャッシュのウェブサイトに、例えば、ローカル使用して実装されるかもしれないが(メモ化の通常の例では、フィボナッチ数は、満足ではない - の範囲Rの数値表現をオーバーフローさせない数値は小さいので、おそらく効率的に事前計算された値のルックアップテーブルを使用するだろう)。ここではクローラがシングルトンであることに興味があります。ファクトリパターンを簡単にたどることができるため、ベースURLごとに1つのクローラを作成できます。

+1

'local'が便利なもう一つのパターンはメモです。 The R Infernoのどこかに例があります。 – otsaw

+0

クローラがシングルトンであるというあなたの考えは面白いです。なぜなら、ローカルの代わりに、無名の関数を引数なしで即座に評価することがあるからです。ファクトリパターンはベースURLに対してクロージャを使用するかもしれません。 – hadley

関連する問題