COLOR(red){SIZE(30){R でマクロを実現する関数}} // 間瀬 2003/7/11 次の関数 COLOR(red){defmacro} はパラメータ付きのマクロを定義する。C 言語に慣れ た人には便利かも知れない。この関数の本来の目的は、~ 複数の関数で(幾つかのパラメータ値を除いて)同一の部分をマクロにしておき、コードを簡潔かつ統一的にすることである。 注:マクロは実行時に定義内容がコード中にまず展開され、その後実行される。 #contents *関数のコード defmacro <- function(..., expr) { # ... には任意個のパラメータ引数 (零個不可)、expr には R の表現式 # by T. Lumley, in "Macros in R" in Rnwes, Vol. 1/3, Sep. (2001) より # 使用例 # mcr <- defmacro(x, y, expr=x*exp(y)) # パラメータ x, y を持つマクロ定義 # foo <- function (x) x*mcr(2, 3) # foo は x*2*exp(3) になる # expr <- substitute(expr) a <- substitute(list(...))[-1] nn <- names(a) if (is.null(nn)) nn <- rep("", length(a)) for (i in seq(length = length(a))) { if (nn[i] == "") { nn[[i]] <- paste(a[[i]]) msg <- paste(a[[i]], "not supplied") a[[i]] <- substitute(stop(foo), list(foo = msg)) } } names(a) <- nn a <- as.list(a) ff <- eval(substitute( function () { tmp <- substitute(body) eval(tmp, parent.frame()) }, list(body = expr))) formals(ff) <- a mm <- match.call() mm$expr <- NULL mm[[1]] <- as.name("macro") attr(ff, "source") <- c(deparse(mm), deparse(expr)) ff } *使用例 > mcr <- defmacro(a, expr=readline("Input a number -> ")) # a はダミーパラメータ > mcr(0) # パラメータ 0 は無意味 Input a number -> 3 [1] "3" > foo <- function (x) x + as.numeric(mcr(0)) # mcr(0) の返す値は文字列なので数値化 > foo(4) Input a number -> 5 [1] 9 # 4 + 5 > mcr <- defmacro(x, y, expr=exp(x)*sin(y)) # パラメータが二個のマクロ > mcr # マクロの定義内容 macro(x, y) exp(x) * sin(y) <environment: 0x9065944> > mcr(2, 3) # マクロを単独で実行(まるで関数そのものに見える) [1] 1.042744 > foo <- function (x) x*mcr(2, 3) > foo(1) [1] 1.042744 # 1*exp(2)*sin(3) > mcr <- defmacro(i, j, k, expr=i*(j+k)) > mcr(2,3,4) [1] 14 これだけなら関数で足りること。マクロでなくちゃというもう少し気の効いた例はないものか? *コメント 1 次の例は,関数を使わない方が好ましい例かもしれません。 こんなことをしなくてもと思う場合には, jugemujugemugokounosurikire <- jugemujugemugookounosurikire*(kaijarisuigyo+3) みたいな例((左辺の変数は右辺の長い変数と同じつもりをタイプミスした例))をわざわざ挙げたり。 C 言語みたいに +<-,-<-, *<-, /<- みたいなの((C 言語などでは, x *= y+1 は,x = x*(y+1) と同じことを表す代入演算子))があれば((割り込みコメント。[[二項演算子定義の例]] を参照して下さい。))いいのだけど。 > mul <- defmacro(x, y, expr=x <- x*(y)) > x <- 2 > y <- 4 > mul(x, y+1) > x [1] 10