Japan.R 2018 LT

関数魔改造講座
(formals編)


atusy

2018-11-30

atusy

関数改造事始

改造は人の業

recyclebin 有意差でたよっ

hoxo-m R で関数のデフォルト引数を変更する(魔改造編)

yutannihilation メモ:httr::oauth2.0_token()のredirect_uriを変える

niszet0 (R) skimrの表示をカスタマイズしたい 3回目(追記修正)

ラッパー関数を作る

名前空間に殴り込む

assignInNamespace()

  • メリット
    • 内部変数を弄ることも含め、何でもできる
    • formals が対象なら便利なパッケージがある
      (hoxo-m/fixer)
  • デメリット
    • オブジェクト間の依存関係による予期せぬ副作用

関数の構成要素を魔改造する

構成要素 > identity
formals 引数のリスト function (x)
body 関数内のコード x
environment 関数を格納した変数の居場所 <environment: namespace:base>

formals() を弄って

assignInNamespace() せずに

内部変数も含めて挙動を弄ろう

package:japanr2018

インストール & 読み込み

中身

namespace:japanr2018 に隔離

japanr2018::f は上書きされない

既存の引数を弄る

formals() で関数の引数を確認する

ヘンなリストだけどリストのノリで弄れる。

弄るには`formals<-`

## $a
## [1] 1
## [1] 2

alist() を使うと遅延評価できる

## rnorm(1)
## [1] 3.439521
## [1] 0.649811

?formals にも載ってるアブナい技

You can overwrite the formal arguments of a function (though this is advanced, dangerous coding).
f <- function(x) a + b
formals(f) <- alist(a = , b = 3)
f # function(a, b = 3) a + b
f(2) # result = 5

引数を追加する

確認

## function(a) a + b
## <bytecode: 0x4b4b6f8>
## <environment: namespace:japanr2018>
## [1] 1

ba と同じ長さの乱数にしたい

## [1] 1.438568 2.591437 3.015478
## [1] 1.994207 2.425113 3.596890 4.074767

たし算じゃなくてかけ算がいい

## [1] 1

japanr2018::g は影響を受けない

## [1] 2

assignInNamespace("b", 2, "japanr2018")

していたら

japanr2018::g(1) == 3

になっていた

応用1
ggplot2で密度分布の信頼区間を描写

ggprotoStatCI を定義

ggplot2::stat_density()
stat_ci() に改造

## function (mapping = NULL, data = NULL, geom = "area", position = "stack", 
##     ..., bw = "nrd0", adjust = 1, kernel = "gaussian", n = 512, 
##     trim = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) 
## {
##     layer(data = data, mapping = mapping, stat = StatDensity, 
##         geom = geom, position = position, show.legend = show.legend, 
##         inherit.aes = inherit.aes, params = list(bw = bw, adjust = adjust, 
##             kernel = kernel, n = n, trim = trim, na.rm = na.rm, 
##             ...))
## }
## <bytecode: 0x5fe15d0>
## <environment: namespace:ggplot2>

stat_density() が呼び出す StatDensity を、
ggplot2::StatDensity から、引数の StatDensity に摩り替え

実際には StatDensity 引数を弄れないよう、もう一工夫した。

Disclaimer

遊び半分の実装です。

実用的には ggdistributebayseplot があります。

応用2
skimr::inline_hist()
ビン数を変更

内部変数 skimr:::optioins を弄る

## ▇▁▁▂▅▅▃▁
## ▁▇▂▁▁▁▁▁▁▁▃▃▃▅▂▃▂▁▁▁

Inspired by niszet0

動的に optioins を弄る

応用3
関数を手抜きして作る

S3メソッドを手抜きして作る

## Printing atusy class object.
## [1] 1
## attr(,"class")
## [1] "atusy"

S3メソッドは最低でも、
総称関数と同じ引数を持たなければならない

`formals<-`() を使えば総称関数の引数を丸々引き継げる