Rの自作パッケージ内で依存パッケージを読み込む方法(Rで顔文字演算子)
今回はRで顔文字演算子を作ることができる話…ではなく、Rの自作パッケージ内でどうやってパッケージを読み込むかについての話である。
Rでパッケージを自作していると、自作パッケージ内で依存パッケージをどのように読み込むかという問題に当たる。
例えば、自作しているパッケージでは、ガツガツmagrittr
やdplyr
を使っている。
これらは、Rのbase
のデータフレーム操作の関数よりもコードをすっきり書けるのでよい。
特にmagrittr
のパイプが素晴らしい。
library(dplyr)
library(magrittr)
iris %>%
filter(Species != "setosa") %>%
select(-starts_with("Sepal")) %>%
mutate(petal_area = Petal.Length * Petal.Width * 0.5) %>%
group_by(Species) %>%
summarise_all(funs(mean))
しかし、ここで問題なのは、
library(dplyr)
library(magrittr)
である。
普通に使い捨てのスクリプトを書いているときは、これで問題ない。
しかし、自作のパッケージの中で、library(x)
を使ってパッケージを読み込むのはNGであるようだ。
http://r-pkgs.had.co.nz/namespace.html
そもそも、library(x)
は何をしているのか。これはパッケージを「アタッチ」している。アタッチとは、サーチパスにパッケージの名前を入れることであり、Rの何らかの関数が呼び出されるとき、まずはこのサーチパスの中に入っている名前空間から関数が検索される。
そして、サーチパスに入っているパッケージについては、わざわざその名前空間を指定しなくても、関数を呼び出すことができる。
library(dplyr)
filter(iris, Species != "setosa")
たしかに、これによってタイピング量を減らすことはできるのだが、パッケージの名前空間を丸ごとサーチパスに入れるため、場合によっては、予期せぬ関数名の衝突を起こす可能性がある。そのため、パッケージレベルではlibrary(x)
の使用はNGとなっている。(個人とか会社のチーム内で使うとか、そういうレベルのパッケージならいいかもしれないが…)
そのため、パッケージ内では、基本的に
dplyr::filter()
のように名前空間を指定して、関数を呼び出すのが基本となる。
そうすると、困ることが一点だけある。
あの美しいパイプラインを実現してくれていた、magrittr
のパイプ演算子(%>%
)である。
実はこのパイプ演算子、名前空間を指定して使おうとすると、二項演算子ではなく関数として認識されてしまう。
(まあ、名前空間つきで使えたとしても、そんな冗長な二項演算子使う人もいないだろうが…)
magrittr::`%>%`(ihs, rhs)
それでは、パッケージ内では%>%
を演算子として使えないということになってしまう。
ところがどっこい、Rには裏技があったようだ。 「スペシャル演算子定義」である。
https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Special-operators
Rでは、下のように%
で囲むと、お手軽に新しい演算子を定義することができる。
そして、%
の中にはどんな文字列を入れてやってもよい。まさにやりたい放題できるというわけだ。
ちなみに、これは既存の演算子のオーバーロードという生易しいやつではない。
(言語仕様的に適切なのだろうか…)
例えば、+
のエイリアスを作ることできる。
`%+%` <- function(a, b) { return(a + b) }
1 %+% 2 # 3
同じようにすれば、magrittr
の%>%
問題も万事解決する。
# library(magrittr)
# 演算子エイリアス
`%>%` <- magrittr::`%>%`
# 使える
iris %>% dplyr::filter(Species != "setosa")
これを使えば、Rでは顔文字演算子なども簡単に作れたりしてしまう。
`%アワワヽ(´Д`;≡;´Д`)ノアワワ%` <- function(a, b){ print("詰み") }
"バグ" %アワワヽ(´Д`;≡;´Д`)ノアワワ% "障害"
# 詰み