初めて遅延評価勉強したのはいつだったかなあ。いつだったかは覚えてないけど、Haskellで勉強した気がします。遅延評価が効果を発揮するのは評価しないで持っておく、例えば、たらいまわしの計算とかはその典型です。Rでのたらいまわしは昔やっていたりします。
www.yasuhisay.info
効用よりデメリット?
で、まあ通常はたらいを回さないので、あんまり効用が得られません。あと思わぬところではまったりするので、「効用というより、デメリットじゃねーの?」と思っている時期もありました。卒論のときに「関数を返す関数」というのをやたらやったんですが、その時です。www.yasuhisay.info
例として
hoge <- function(x1,x2){ x1 <- x1 x2 <- x2 return(function(y){ cat(x1,x2,fill=TRUE) x1*x2*y}) }
という関数があったときに、
x1 <- x1 x2 <- x2
と書いてやらないと、戻り値となる関数
return(function(y){ cat(x1,x2,fill=TRUE) x1*x2*y}) }
の"環境(envirnment)"の中で評価されていないので、使えないということが起きてしまいます。たぶん、これは慣れてないと引っかかるポイントだと思う(僕は大分引っかかりました)。
違うよ、全然違うよ!!
こういうことがあったので遅延評価の恩恵はなんなのかよく分かってませんでした。Rにはevalがあるので、文字列を生成して、evalで評価!!ということができますが、Rの文字列関係の関数は使い勝手がそれほどよくはないので、evalのための文字列生成で結構疲れます。「じゃあ、evalじゃなくてRの表現式(expression)そのまま持っておけばよくね?」という感じの考えに行きつくのですが、Rならできます。それがこの前書いたところです。これは非常に強力です。
簡単な例が載っているのがあったので紹介します。
評価されたものと、評価される前の表現式オブジェクト、というのがよく分かります。
> label <- function(x) {list(value=x,actual=substitute(x))} > label(1+1) $value [1] 2 $actual 1 + 1
こういう感じで遅延評価と表現式オブジェクトを組み合わせるとより強力になります。
例
loggerなんか作ろうぜ、と思って作ったはいいんだけどちょっとへぼすぎる感じです(笑)。loggerとしてはへぼいけど、Rの遅延評価の例としてはまあいいかなあと思って載せることにします。コンストラクタにinfoと与えると何も表示しない、debugとやるとそこに投げられたものは表示する、dmとやると実験が終わったらtwitterのdmで伝える(gemのtwitterが必要です)というような(loggerと呼んでいいのかよく分からない)loggerです。
setClass( Class="logger", representation=representation( level = "character", d = "character" #dm for twitter ), prototype=prototype( level = "info", d = character() ) ) setGeneric("logging",function(x,expr){standardGeneric("logging")}) setMethod(f="logging", signature= "logger", definition=function(x,expr){ if(any(x@level == "info")){ } if(any(x@level == "debug")){ expr } if(any(x@level == "dm")){ expr system(paste("twitter d ",x@d," finished at ",date(),sep="")) } return(invisible()) }) l <- new("logger",level=c("info"),d="syou6162") logging(l,print(1:10)) for(i in 1:100){ Sys.sleep(1) logging(l,print(1:10)) }
遅延評価になっているところは
logging(l,print(1:10))
の部分です。print(1:10)のところに任意のRの表現を書けるので、logに出力するとき非常に便利な気がします。