メモ:Rの関数の引数

よく分からない質問が来たのでメモ。

関数の引数の記法

どういう関数のシグネチャが優れているのか考える前にまず、関数の引数の書き方についておさらいしておきましょう。

関数の引数のマッチング方法

引数のマッチング方法には3つの種類があります(用語は正しいかわからないけどまあメモ用ということで)。

  • positional matching: 引数の位置でマッチングする
  • partial matching: 引数の名前の前方一致でマッチングする
  • exact matching: 引数の名前の完全一致でマッチングする

例えば、ggplot()の1番目の引数はdataですが、これに値を渡すには3つのやり方があります。

# positional
ggplot(iris)

# partial
ggplot(d = iris)

# exact
ggplot(data = iris)

しかし、このうちpartial matchingは予期せぬミスを招きやすいので使っちゃダメ、というのが暗黙の了解になっています。 以下のように設定すれば警告を出すことができます。$@のpartial matchingについても、warnPartialMatchDollarwarnPartialMatchAttrというオプションがそれぞれ用意されています。

options(warnPartialMatchArgs = TRUE)

残りのpositional matchingとexact matchingについては、Advaned Rによれば、1番目と2番目の引数にはpositional matchingでよくて、残りはexact matchingを使うように、となっています。

Generally, only use positional matching for the first one or two arguments; they will be the most commonly used, and most readers will know what they are. Avoid using positional matching for less commonly used arguments, and never use partial matching.

デフォルト値

関数はデフォルト値を指定することができます。

例えば、以下の関数のうち、f1()xyを指定せずに呼び出しても動きますが、f2()はエラーになります。

f1 <- function(x = 1, y = 2) x + y
f2 <- function(x, y) x +y

...

...はマッチしなかった引数すべてにマッチします。例えば、以下のような関数だと、xにもyにもマッチしない引数が...に吸収されます。

f <- function(x, y, ...) {
  list(...)
}

具体的には、こんな感じです。

f(
  1,        # 位置が1番目、かつ他に「x =」を指定している引数がないのでxにマッチする
  z = 2,    # 「z =」を指定しているのでxにもyにもマッチせず、...に落ちる
  y = 3,    # 「y =」を指定しているのでyにマッチする
  4        # x, yはすでにマッチした引数があるので、いずれにもマッチせず...に落ちる
)
#> $`z`
#> [1] 2
#> 
#> [[2]]
#> [1] 4

ちなみに、...の中の引数は、list(...)に渡さなくても、..1とか...elt(2)で参照可能です(さっき知った)。

f <- function(x, y, ...) {
    cat("...の1番目は", ..1)
    cat("\n")
    cat("...の2番目は", ...elt(2))
}

関数の引数、こんなときどうする

基礎知識は出揃ったので、具体的にどう使うか書いていきます。

ユーザに必ず指定させたい引数

必須の引数には、デフォルト値を設定してはいけません。 さっき上で書いた例を再掲。

# x、yは必須にはなってない
f1 <- function(x = 1, y = 2) x + y

# x、yは必須
f2 <- function(x, y) x +y

必須ではないが、指定するなら必ず名前付きで指定させたい引数

このタイプの引数は....の後ろに置きます。 こうすると、xy以外に名前なしで指定された引数はすべて...に吸収されます。 こうしておくと、na.rmを指定するためにはna.rm =と指定しなくてはいけないようになります。

f <- function(x, y, ..., na.rm = TRUE)

必ず名前付きで指定させたい引数

デフォルト値を指定しなければ必須の引数になります。

f <- function(x, y, ..., na.rm)

これはむずい

まだうまいやり方がないやつもいくつかあります。

意図しない名前が指定されたらエラーにしたい

...を使った副作用として、うっかり引数の名前を間違えてもエラーにならない、という問題があります。 たとえば、na.rmna.mrとタイポしてもエラーになりません。これは...にマッチしてしまうからです。

f(1, 2, na.mr = TRUE)

この問題に関しては、Hadleyがなにかレポジトリをつくっているようなので、これがそのうち解決策になるでしょう。たぶん。

missingnessを伝播させたい

これはまあ、あんまり困ってる人いないと思うんですけど。 デフォルト値があるとmissingnessは伝播しません。

例えば、ggplot2はmissingnessを表すためにwaiver()という特殊なオブジェクトをわざわざつくっています。 なかなかこれを一般的に解決する方法はなさそうです。