rtypeで型安全なR?
とか書いとくと、「型安全」とは何か、みたいなマサカリが飛んできて勉強になりそうなのでこういうタイトルにしています。 型安全って何なのかあまり理解できてないので、コメント欄とかTwitter(@yutannihilation)でこっそり教えていただけると助かります。
さて、本題です。Rで関数の引数に型を指定できるパッケージができたらしいです。
といっても、Experimentってばっちり書いてあるので、そのうち名前も使い方も変わる気がします。使い方を覚えるのは尚早な雰囲気ですが、とりあえず触ってみたところをメモ。
インストール
devtools::install_github("romainfrancois/rtype")
使い方
rtypeでは、function()
の代わりにfunction_()
を使います。
READMEに載ってる例はこんな感じ。
library(rtype) f <- function_(integer: n ~ 3L, character: txt ~ "foo", { rep(txt, n) })
n
はinterger型でデフォルト値は3L
、txt
はcharacter型でデフォルト値は"foo"
です。
これを動かしてみます。integer型なので4L
は通りますが4
は通りません。
f(4L, "アッハイ") #> [1] "アッハイ" "アッハイ" "アッハイ" "アッハイ" f(4, "アッハイ") #> Error: n is not of type integer
自分で型をつくる
この時実際に呼ばれているのはtype_check()
というS3メソッドです。それぞれのクラスに対応する型チェックが行われます。
obj <- ls(envir = asNamespace('rtype')) grep("^type_check.+", obj, value = TRUE) #> [1] "type_check" "type_check.character" "type_check.default" "type_check.integer" #> [5] "type_check.logical" "type_check.numeric"
なので、type_check.クラス名()
という関数をつくってやれば、それが型のチェックに使われます。例えば、長さ1のintegerのinteger_scalar
というクラスがあるとします。そのチェックはこんな感じでできます。
type_check.integer_scalar <- function(value, type, name) { if(type != "integer_scalar" || is.na(as.integer(value)) || length(value) != 1) stop(sprintf("%s is not a valid integer_scalar.", call. = FALSE)) } f <- function_(integer_scalar:n, {cat(n)}) a <- 1 class(a) <- "integer_scalar" f(a) #> 1 b <- 1:3 class(b) <- "integer_scalar" f(b) #> Error in type_check.integer_scalar(n, "integer_scalar", "n") : #> FALSE is not a valid integer_scalar.
S3以外のクラスシステムとの親和性は、...よく分からないので誰か書いてください!