R

関数の中身とヘルプを同時にすぐ見たい(felp me!)

2018/3/2の第68回TokyoRに参加してきました。
その懇親会でniszetさんとigjitさんとお話し、関数のヘルプ見る時?関数という書き方は面倒だよねという話をしました。
できたら関数?という書き方をしたいけど多分無理だよね、という話をしていました。
無理ゲーと思いつつ、RStduioなら左右のペーンを利用してヘルプと同時に関数のソースも見たいと要望は募るばかり。
そんなfunction help略してfelpパッケージに挑戦しようという話になりました。

雛形

関数のヘルプを見るにはhelp、ソースを見るにはprint.functionを用います。
後者は所謂総称的関数printのmethodの一つ(S3 generic)です。
これらを組合せればヘルプとソースを同時に見るfelp関数を作れるはず。
出来上がったのが以下。

felp <- function(x, ...) {
  base::print(help(deparse(substitute(x)), ...))
  base::print.function(x, ...)
}

このfelp関数を用い、

felp(help)

とすれば、helpのソースとヘルプを同時に見る事ができます。

ポイントは4点。

  • felp(x)のxを非標準評価する
    • help(x)とすると、xという名前の関数のヘルプを探してしまう。
    • help(deparse(substitute(x)))ならOK
  • helpを明示的にprintする
    • helpprintの中に入れないと、ヘルプは表示されずソースコードしか見れません。
    • これはRにおいては関数内で実行された結果の内、自動にprintされるのは最後に実行された行のみだからです。
  • print.functionbase::print.functionとし、出自を明らかにする
    • 雛形段階では重要ではありません。
    • 最終的にprint.functionを新たに定義してマスクし、関数と打つだけでヘルプとソースを見るための布石です。
  • ...を使うことで、helpprint.functionに引数を適宜パスする
    • これにより、felp(select, package = 'MASS')といった具合にどのパッケージの関数についてヘルプを見たいか、選択できるようになります。
    • ただし、雛形段階ではソースを表示する関数がどのパッケージ由来かを選ぶことができません(最も近い環境のものが選ばれる)。

発展させたいが……!

さて、print.function <- felpとすると、helpと入力するだけで、helpのヘルプとソースが呼び出されるようになりそうです。
しかし、実際にはこれはうまく行きません。

No documentation for ‘x’ in specified packages and libraries:
you could try ‘??x’

という文字列の後にhelpのソースが表示され、ヘルプが表示されないのです。
その原因には心当たりがあります。2018/03/03 13:13 以下は勘違いでした。原因は根深そうです。print(x = help)はちゃんと動きます。もっと問題は根深そうです。yutanihilationさん、ご指摘ありがとうございます。

S3 genericを利用しているため、helpを入力した時、実行されているコードは以下です。

print(x = help)

この時helpはfunctionですので、適したmethodとしてprint.functionを呼び出し、その引数xxを与えます。

print.function(x = x)

結果、現在の実装では、deparse(substitute(x))の部分が"x"を返します。
しかしながら、xだなんて関数は定義されていtopicはないよと怒られるわけです。
仕様の壁にぶちあたった気がしますが、うまい回避法があれば、ご提案下さい。

2018/03/03 11:25
helpの第一引数はtopicなので、「xだなんて関数は定義されていない」というのは実態に即していないとの指摘をyutanihilationさんから頂き、「topicはない」に修正しました。
ご指摘ありがとうございます。