引数の評価についての認識間違い
前回(id:eji:20120619)の遅延ストリームを使った解答に若干修正を加えました。
stream.end <- function(msg) { msg == "eos" } stream.make <- function(head, tail) { function(msg) { if (msg == "eos") F else if (msg == "head") { head } else if (msg == "tail") { tail } } } stream.is_end <- function(s) { s("eos") } stream.head <- function(s) { s("head") } stream.tail <- function(s) { s("tail") } stream.take <- function(n, st) { if (n <= 0 || stream.is_end(st)) { stream.end } else { stream.make( stream.head(st), stream.take(n-1, stream.tail(st)) ) } } stream.take_while <- function(pred, st) { head <- stream.head(st) if (pred(head)) { stream.make( head, stream.take_while(pred, stream.tail(st)) ) } else { stream.end } } stream.fold <- function(fn, init, st) { if (stream.is_end(st)) init else { stream.fold( fn, fn(init, stream.head(st)), stream.tail(st) ) } } stream.sum <- function(stream) { stream.fold( function(a, b) { a + b }, 0, stream ) } stream.filter <- function(pred, st) { head <- stream.head(st) tail <- stream.tail(st) if (stream.is_end(st)) st else if (pred(head)) { stream.make( head, stream.filter(pred, tail) ) } else { stream.filter(pred, tail) } } stream.fib <- (function() { fibgen <- function(a, b) { stream.make( a, fibgen(b, a+b) ) } fibgen(1, 2) })() even <- function(n) { (n %% 2) == 0 } answer <- stream.sum( stream.take_while( function(n) { n < 4000000 }, stream.filter(even, stream.fib) ) ) cat("answer:", answer, "\n")
遅延評価のためにクロージャで包んでいたストリームの残りを、クロージャで包まないようにしました。Rでは渡された実引数が必要になった時に初めて評価されるため、わざわざクロージャで包んで評価を遅らせる必要がないようです。
例えば、Schemeのような正格評価の言語の場合、以下のようなコードでは第2引数に渡された値は(順番はどうあれ)評価されてしまいます。
; scheme > (define (func a b) a) func > (func 3 (display "hoge\n")) hoge 3 >
しかし、Rの場合は引数の値が全く利用されなければ評価されません。
# R > func <- function(a, b) a > func(3, cat("hoge\n")) 3 >
RはHaskellと同じように非正格評価の言語なのかな...?