33. 引数について


引数のチェックを行う

特定の引数に対して関数の手続きを変更したい場合は,if 文などの条件分岐で場合分けをすればよい.以下の関数 myprod() は引数 n が 0 の時に 1 を返す.

 
 myprod <- function(n) {
   if (n==0) 1
   else      prod(1:n)
 }
 myprod(0)

[1] 1

 myprod(5)

[1] 120

また,引数のチェックを行う場合,関数 ifelse() も有用となる.

 
 myprod <- function (n) {
   ifelse(n==0, 1, prod(1:n))
 }
 myprod(0)

[1] 1

 myprod(5)

[1] 120

引数の省略

組み込み関数には引数の省略を許すものが多くあるが,自分で定義した関数でも引数の省略を許すように作ることが出来る.これを実現する方法は次の2つがある.

【引数の宣言部で指定する方法】
まず,引数の宣言部で,引数に対する指定値が省略された時の値を指定する方法を示す. 例えば以下のような関数を定義すると y は省略可能な引数となり,省略した場合の y の値は 1 となる.

 
 mymultiply <- function(x, y=1) {
   return(x*y)
 }
 mymultiply(2,5)

[1] 10

 mymultiply(2)

[1] 2

また,省略時の値を指定する部分に任意の好きな式を書くことも出来る上,式の中で他の引数を参照することも可能である.

 
 mymultiply <- function(x, y=x^2) {
   return(x*y)
 }
 mymultiply(2,5)

[1] 10

 mymultiply(2)

[1] 8

ただし,以下のように引数を互いに参照しあう定義を行った場合,どちらかの引数を与えて関数を呼び出せば問題はないが,引数無しで関数を呼び出すとエラーになる.

 
 myfunc <- function(x=2*y, y=x^2) {
   return(x*y)
 } 
 myfunc(2)

[1] 8

 myfunc()

以下にエラー myfunc() : 既定引数の再帰的な参照です

【関数missing()を使う方法】
関数 missing() を使って,ある引数が実際に存在するかどうか,引数が省略されたかどうかを調べる方法もある.関数 missing() は,指定された引数に対する値が省略されていれば TRUE を返す.

ただし,missing(y) は y が関数中で変更されると信頼できなくなる(例:y <- match.arg() の後では必ず FALSE になる)

また,関数 missing() によって,引数への値が省略されたかどうかを調べることも出来る.以下では,変数 y が省略されたときに関数 missing() と関数 warning() を用いて警告を表示している.

 
 mymultiply <- function(x, y) {
   if (missing(y)) return(x)
   else return(x*y)
 }
 mymultiply(2,5)

[1] 10

 mymultiply(2)

[1] 2

 mymultiply <- function(x, y=1) {
   if (missing(y)) warning("y isn't inputted.")
   return(x*y)
 }
 mymultiply(3,2)

[1] 6

 mymultiply(2)

[1] 2
警告メッセージ: y isn't inputted. in: mymultiply(2) 

任意個の引数を受けとる

例えば,関数 c() は引数の個数の制限が無く,2 個でも 10 個でも好きなだけ引数を与えることが出来る.このような任意個の引数を自作する場合,記号 ... で表される特殊な引数を使えばよい.また,関数の引数 ... の後にさらに引数を持つ関数を定義することも出来る.ただし,関数の呼出時にはこのような引数 ... は必ず【 名前 = 値 】の形で与えなければならず,引数名の省略も許されないので注意.

 
 f <- function(x, ...) {
   label <- deparse(
             substitute(x)
            )
   plot(x, xlab=label, ...)
 }
 x <- 1:10
 f(x, ylab="y")        # 図は省略

 g <- function(...) {
   args <- list(...)
   return(args)
 } 
 f(1:6, "title")

[[1]]
[1]  1  2  3  4  5  6

[[2]]
[1] "title"

 h <- function(... , y=1) {
   2*y
 }
 h(5)

[1] 2

 h(5,y=2)

[1] 4

 h(y=2)

[1] 4

引数に関数を与える

例えば関数 apply() は引数に関数をとることが出来る.これは,R の関数には引数としてオブジェクトを与えており,関数もオブジェクトであることから,以下のように引数に関数オブジェクトを与えることが出来るからである(以下の内容は『RjpWiki』の記事を参考にして作成した).これは自分で定義した関数にも当てはまり,右下のように,引数に関数をとることができる関数を自作することも出来る.

 
 apply(matrix(1:4,2),1,function(x) { 2*x } )

     [,1] [,2]
[1,]    2    4
[2,]    6    8

 f <- function(x, Fun) Fun(x)
 f(3, sqrt)

[1] 1.732051

 g <- function(x, Fun=sqrt) Fun(x) 
 g(5)

[1] 2.236068

関数 apply() の例のように,関数定義を直接与えることも出来る.また,関数自身がオプション引数をもち、それを特定の値に指定したいときは以下のようにする.

 
 x <- c(1, 4, 9, 16, 25, 36)
 f <- function(x, Fun) Fun(x)
 f(x, F=function(z) {2*z})

[1]  2  8 18 32 50 72

 mean(x)

[1] 15.16667

 F <- function(x, a=0)   mean(x, a)
 g <- function(x, a, fun) fun(x, a)
 g(x, 0.4, F)

[1] 12.5

引数のマッチングと選択

関数の引数は省略形で指定することが出来る.すなわち,綴りの途中までだけで特定の引数であることが認識できれば,引数をある程度省略して記述することが出来る.これを部分的マッチングと呼ぶ.ただし,以下では "xl" から "xlab" が認識できずに("xlim" の可能性もあるので)エラーが出ている.

 
 plot(sin, xlab = "x-title")     # x 軸にタイトルをつける
 plot(sin, xla  = "x-title")     # "xla" でも "xlab" と分かる
 plot(sin, xl   = "x-title")     # "xl" では "xlab" と分からない

Error in if (from == to || length.out < 2) by <- 1 : missing value where TRUE/FALSE needed

関数の引数に与えられた値が候補のどれに一致するかどうかをチェックする場合は関数 match.arg() を用いる(このとき部分的マッチングが行われる).ただし,該当する項目がなければエラーが出る.

 
 myfunc <- function(a, b, do = c("sum", "minus", "multi", "div")) {
   do <- match.arg(do)
   switch(do, sum   = a+b,       # do (match.arg の返り値) 
              minus = a-b,       # の結果で条件分岐
              multi = a*b,
              div   = a/b)
 }
 myfunc(3, 2, "minus")

[1] 1

 myfunc(3, 2, "mi")              # 引数:"mi" でも "minus" だと分かる

[1] 1

 myfunc(3, 2, "m")               # "m" では "minus" だと分からない...

Error in match.arg(do) : ARG should be one of sum, minus, mult, div