R でマクロを実現する関数
次の関数 defmacro はパラメータ付きのマクロを定義する。C 言語に慣れ
た人には便利かも知れない。この関数の本来の目的は、
複数の関数で(幾つかのパラメータ値を除いて)同一の部分をマクロにしておき、コードを簡潔かつ統一的にすることである。
注:マクロは実行時に定義内容がコード中にまず展開され、その後実行される。
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
これだけなら関数で足りること。マクロでなくちゃというもう少し気の効いた例はないものか?
次の例は,関数を使わない方が好ましい例かもしれません。
こんなことをしなくてもと思う場合には,
jugemujugemugokounosurikire <- jugemujugemugookounosurikire*(kaijarisuigyo+3)
みたいな例*1をわざわざ挙げたり。
C 言語みたいに +<-,-<-, *<-, /<- みたいなの*2があれば*3いいのだけど。
> mul <- defmacro(x, y, expr=x <- x*(y)) > x <- 2 > y <- 4 > mul(x, y+1) > x [1] 10