Rの自作パッケージ内で依存パッケージを読み込む方法(Rで顔文字演算子)

今回はRで顔文字演算子を作ることができる話...ではなく、Rの自作パッケージ内でどうやってパッケージを読み込むかについての話である。

Rでパッケージを自作していると、自作パッケージ内で依存パッケージをどのように読み込むかという問題に当たる。

例えば、自作しているパッケージでは、ガツガツmagrittrdplyrを使っている。
これらは、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("詰み") }

"バグ" %アワワヽ(´Д`;≡;´Д`)ノアワワ% "障害"

# 詰み