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