R を使ったことがある人は,おそらくすべての人が c
関数を使ったことがあるでしょう。 c
関数は,複数のベクトルやリストを連結する関数です。例えば c(1, 2, 3)
は, 3 つの長さ 1 のベクトルを連結します。
c
のヘルプを見ると,使用方法は次のようになっています[A]。
c(..., recursive = FALSE)
引数の ...
は「連結されるオブジェクト」であると説明があります。したがって,最初の例では 3 つのベクトルが ...
に格納されていることになります。なぜ 1 つの ...
という変数に, 3 つのベクトルが格納されるのでしょうか。
...
は dot-dot-dot オブジェクトと呼ばれる特殊なオブジェクトです。これは関数の引数に利用され,他の引数以外のすべての引数が格納されます。 c
関数の例では, recursive
という名前の引数以外が ...
に格納されることになります。これの何が便利かというと,関数の内部で呼ぶ関数の引数を,すべて明示する必要がないということです。わかり易い例では read.csv
関数があります。ソースコード[B]を見ると read.csv
は次の様に定義されています。
read.csv <- function (file, header = TRUE, sep = ",", quote = "\"", dec = ".", fill = TRUE, comment.char = "", ...) read.table(file = file, header = header, sep = sep, quote = quote, dec = dec, fill = fill, comment.char = comment.char, ...)
内部で呼ばれる read.table
には stringAsFactors
や blank.lines.skip
のように他にも沢山引数があるのですが,これらすべてを ...
という,見かけ上 1 つの引数に委譲することができています。他に plot
をはじめとする描画系の関数でもよく用いられます。
このように dot-dot-dot オブジェクトを用いることで,その関数にとって本質でない引数を隠しつつも,実際には引数を受け取るというようなことが可能です。うまく dot-dot-dot オブジェクトを使い,柔軟かつ理解しやすい関数を作ると良いでしょう。
おまけ
基本的に引数として受けた ...
はそのまま他の関数に渡せば良いのですが, ...
の要素にアクセスしたい場合があるかもしれません。 ...
は特殊なオブジェクトであるため, ...
の要素へのアクセスは特殊な記法があります。要素の先頭から ..1
, ..2
,という具合に ..n
という名前でアクセスすることができます。
f <- function(x, ...) ..1 f(1, 2, 3) # 2 f(1, x=2, 3) # 1
また, list
関数や as.list
関数に与えてやれば,リストになるので,通常のリストとして扱うこともできます。
g <- function(...) list(...) g(x=1, y=2)$y # 2
脚注
- R 2.15.3 の場合。 [↩]
- readtable.R [↩]