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

これだけなら関数で足りること。マクロでなくちゃというもう少し気の効いた例はないものか?

コメント 1

次の例は,関数を使わない方が好ましい例かもしれません。

こんなことをしなくてもと思う場合には,

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

*1 左辺の変数は右辺の長い変数と同じつもりをタイプミスした例
*2 C 言語などでは, x *= y+1 は,x = x*(y+1) と同じことを表す代入演算子
*3 割り込みコメント。二項演算子定義の例 を参照して下さい。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2023-03-25 (土) 11:19:17