2011-12-17 7 views
3

親呼び出しにon.exit exprを追加することはできますか?もしそうなら、どうですか?親呼び出しにon.exit exprを追加しますか?

たとえば、parentOnExit(expr)はこれを実装する関数です。次に、次のコードの場合:

f <- function() { 
    parentOnExit(print("B")) 
    print("A") 
} 

"A"が表示され、次に "B"が表示されます。

背景:これを念頭に置いた理由は次のとおりです。関数のコレクションがあり、そのうちのいくつかは他のものを呼び出します。リソースは最上位の呼び出しから共有される必要があります。最上位の機能を終了します。例えば、オープンするのに高価なリモートサーバへの接続。この一つのパターンは次のとおりです。

foo <- function(r=NULL) { 
    if (is.null(r)) { # If we weren't passed open connection, open one 
    r <- openR() 
    on.exit(close(r)) 
    } 
    bar(r=r) # Pass the open connection down 
} 
私はこれらの3つのラインまでの抽象化に期待していた

:今、私もそれについて考えることを

r <- openIfNull(r) # Magically call on.exit(close(r)) in scope of caller 

、おそらくそれはあまりにも不思議な何かを避けるために、いくつかの繰り返しのコードの価値があります。しかし、私は元の質問に対する答えが不思議です。ありがとうございました!

+0

これは私にとっては意味がありません。目的が関数からオープンな接続を返すことであるなら、なぜあなたは 'on.exit'でそれを閉じますか? –

+0

私はopenIfNullの中でon.exitを呼びたくありません。 openIfNullが新しいオープン接続を返したことを前提に、openIfNullを呼び出す関数のコンテキストで呼び出す必要があります。したがって、openIfNullを呼び出すと、openIfNullが呼び出された関数を終了したときに自動的に新しい接続を閉じるという副作用があります。 (これは会話の種類で、私にとってはこれが悪いことだと確信しています) –

+0

@DavidF - DWinが答えたので、あなたの現在のトップの例はあまり良くありません。単純に 'parentOnExit < - on.exit'を定義すれば、それを解決できます。 – Tommy

答えて

4

私はこの問題に興味を持ち、それを解決するためにいくつかの方法を試しました。残念ながら、彼らはうまくいきませんでした。私はそれができないと信じる傾向があります。 ...しかし、他の人が私を間違っていると証明できるかもしれません!

とにかく、失敗した試行を投稿して記録することはできますが、私は彼らに "ONEXIT!"を印刷させるようにしました。 の後に "まだ!" on.exit関数は、現在のスタックフレームにコンテンツを追加し、おそらくので、

f <- function() { eval(on.exit(cat('ONEXIT!\n')), parent.frame()); 42 } 
g <- function() { x<-f(); cat('Not yet!\n'); x } 
g() # Nope, doesn't work! 

これは動作しません: - 彼らは働いていた場合...

1まず、単純に親環境におけるon.exitを評価しよう現在の環境ではありません。

2 - ゲームをステップアップして、発信者によって評価される式を返すようにしてみてください。

f <- function() { quote({on.exit(cat('ONEXIT!\n')); 42}) } 
g <- function() { x<-eval(f()); cat('Not yet!\n'); x } 
g() # Nope, doesn't work! 

これはevalgは異なる独自のスタックフレームを、持っているためか、いずれかの動作しません。

3 - 私のA-ゲームを持参し、遅延評価に依存しよう:

h <- function(x) sys.frame(sys.nframe()) 
f <- function() { h({cat('Registering\n');on.exit(cat("ONEXIT!\n"));42}) } 
g <- function() { x<-f()$x; cat('Not yet!\n'); x } 
g() # Worse, "ONEXIT!" is never printed... 

この1つは、呼び出し元に、環境を返し、呼び出し側はそれに「X」をアクセスしたとき、式は含みますon.exitが評価されます。 ...この場合、on.exitは全く登録されていないようです。

4 - Hmm。まだ動作している方法があります:.Callon.exitを呼び出すCコードがあります。 Cを呼び出すともう1つのスタックフレームが追加されないかもしれません...これは少し複雑すぎて今テストすることはできませんが、RAPI/RCppの一部の人がそれを打つことができますか?

+0

私はこれを答えとして受け入れます。それを調べてくれてありがとう。 –

+0

??私のdo.callの解決策はあなたのために働かない? –

1

私はまだ混乱していますが、もしトミーがそれを行えないなら、私はどちらもできないだろうと思っています。これは、最初のタスクを行い、それは私が私が何か欠けている必要があります思ったので、簡単なように見えたので、:

f <- function() { 
    on.exit(print("B")) 
    print("A") 
} 

セカンド努力を:

txtB <- textConnection("test b") 
    txt <-textConnection("test A") 
    f <- function(con) { df <- read.table(con); 
        if(isOpen(txtB)){ print("B open") 
          eval(close(txtB), env=.GlobalEnv) } 
        return(df) } 
    txtB #just to make sure it's still open 
#  description   class    mode    text 
# "\"test b\"" "textConnection"    "r"   "text" 
#   opened   can read  can write 
#  "opened"   "yes"    "no" 
    dat <- f(txt); dat 
#[1] "B open" 
# V1 V2 
#1 test A 
txtB 
#Error in summary.connection(x) : invalid connection 

(OK、私が呼び出し環境内で接続を閉じるには、それを編集しました。) 私は何が欠けていますか? (私は接続が実際に環境を持っている、これをテストしたように、それは私には明確ではありませんでした。)

+0

'r < - openIfNull(r)'の例は、彼が何を望んでいるかをより明確に示しています:何かを返す関数( 'r')*を呼び出して' on.exit'式を追加して 'r'をクリーンアップします。 – Tommy

+0

私は2番目の努力で立ち往生しました。私はまだ何かが欠けていますか? –

+0

ここでの質問は、関数 'f1'の中で呼び出された関数' f2'が関数 'f1' *の終了時に*実行される式を記録するために' on.exit'を使用できるかどうかです。 –

7

私はあなたがこのためにdo.callを使用することができ、この最近のメールの議論(https://stat.ethz.ch/pipermail/r-devel/2013-November/067874.html)で見てきた:

f <- function() { do.call("on.exit", list(quote(cat('ONEXIT!\n'))), envir = parent.frame()); 42 } 
g <- function() { x <- f(); cat('Not yet!\n'); x } 
g() 
#Not yet! 
#ONEXIT! 
#[1] 42 
関連する問題