演算子の話

@y__mattu

2019/3/2 Tokyo.R #76

はじめに

誰?

icon

著書

R ユーザのための RStudio[実践]入門
− tidyverse によるモダンな分析フローの世界−

rstudiobook

  • 通称: 「宇宙本
  1. RStudio 入門(@y__mattu)
  2. スクレイピングによるデータ取得(@y__mattu)
  3. dplyr を中心としたデータハンドリング(@yutannihilation)
  4. ggplot2 による可視化(@kyn02666)
  5. R Markdown によるレポーティング(@kazutan)

今日のお話

  • 導入
    • 総称関数
  • 演算子の挙動
    • 関数の実行環境
    • 演算子の中身
  • まとめ

※20分しかないので簡単に。

今日はパッケージ名だけでも
覚えて帰ってくださいねm(_ _)m

本日の目標

これを理解する

result <- 1 + 2
print(result)
[1] 3

とくに result <- 1 + 1 の部分

前回のTokyo.Rで…

宇宙が生まれる前の話

大切なこと

「Rのすべての関数はオブジェクトであり、すべてのオブジェクトは関数である。」

R上での全ての挙動は関数の実行である。」

余談

ここでは何が起こっているのか

print(result)
[1] 3
  • print.default() が実行されている
  • print()総称関数 と呼ばれる関数で、引数の中身(のクラス)によって特定の関数が呼び出される
  • 「メソッドがディスパッチされる」という言い回しをします
  • 他には head(), plot(), summary() など

総称関数1

  • Rでは、関数をカッコ無しでREPLに入れるとその中身が表示される
  • なぜならば、全ての関数はオブジェクトだから
  • 総称関数は、 UseMethod("") という表示が出てくる
print
function (x, ...) 
UseMethod("print")
<bytecode: 0x7f9d26f70a28>
<environment: namespace:base>

総称関数2

メソッド一覧は methods() 関数で見る

methods("print")
  [1] print.AES*                                        
  [2] print.Arima*                                      
  [3] print.AsIs                                        
  [4] print.Bibtex*                                     
  [5] print.CRAN_package_reverse_dependencies_and_views*
  [6] print.DLLInfo                                     
  [7] print.DLLInfoList                                 
  [8] print.DLLRegisteredRoutines                       
  [9] print.Date                                        
 [10] print.Dlist                                       
 [11] print.HoltWinters*                                
 [12] print.LaTeX*                                      
 [13] print.Latex*                                      
 [14] print.MethodsFunction*                            
 [15] print.NativeRoutineList                           
 [16] print.PDF_Array*                                  
 [17] print.PDF_Dictionary*                             
 [18] print.PDF_Indirect_Reference*                     
 [19] print.PDF_Keyword*                                
 [20] print.PDF_Name*                                   
 [21] print.PDF_Stream*                                 
 [22] print.PDF_String*                                 
 [23] print.POSIXct                                     
 [24] print.POSIXlt                                     
 [25] print.RGBcolorConverter*                          
 [26] print.Rcpp_stack_trace*                           
 [27] print.Rd*                                         
 [28] print.StructTS*                                   
 [29] print.TukeyHSD*                                   
 [30] print.acf*                                        
 [31] print.anova*                                      
 [32] print.aov*                                        
 [33] print.aovlist*                                    
 [34] print.ar*                                         
 [35] print.arima0*                                     
 [36] print.aspell*                                     
 [37] print.aspell_inspect_context*                     
 [38] print.bibentry*                                   
 [39] print.browseVignettes*                            
 [40] print.by                                          
 [41] print.bytes*                                      
 [42] print.changedFiles*                               
 [43] print.checkDocFiles*                              
 [44] print.checkDocStyle*                              
 [45] print.checkFF*                                    
 [46] print.checkRd*                                    
 [47] print.checkReplaceFuns*                           
 [48] print.checkS3methods*                             
 [49] print.checkTnF*                                   
 [50] print.checkVignettes*                             
 [51] print.check_Rd_contents*                          
 [52] print.check_Rd_line_widths*                       
 [53] print.check_Rd_metadata*                          
 [54] print.check_Rd_xrefs*                             
 [55] print.check_RegSym_calls*                         
 [56] print.check_T_and_F*                              
 [57] print.check_code_usage_in_package*                
 [58] print.check_compiled_code*                        
 [59] print.check_demo_index*                           
 [60] print.check_depdef*                               
 [61] print.check_details*                              
 [62] print.check_details_changes*                      
 [63] print.check_doi_db*                               
 [64] print.check_dotInternal*                          
 [65] print.check_make_vars*                            
 [66] print.check_nonAPI_calls*                         
 [67] print.check_package_CRAN_incoming*                
 [68] print.check_package_code_assign_to_globalenv*     
 [69] print.check_package_code_attach*                  
 [70] print.check_package_code_data_into_globalenv*     
 [71] print.check_package_code_startup_functions*       
 [72] print.check_package_code_syntax*                  
 [73] print.check_package_code_unload_functions*        
 [74] print.check_package_compact_datasets*             
 [75] print.check_package_datasets*                     
 [76] print.check_package_depends*                      
 [77] print.check_package_description*                  
 [78] print.check_package_description_encoding*         
 [79] print.check_package_license*                      
 [80] print.check_packages_in_dir*                      
 [81] print.check_packages_used*                        
 [82] print.check_po_files*                             
 [83] print.check_pragmas*                              
 [84] print.check_so_symbols*                           
 [85] print.check_url_db*                               
 [86] print.check_vignette_index*                       
 [87] print.citation*                                   
 [88] print.codoc*                                      
 [89] print.codocClasses*                               
 [90] print.codocData*                                  
 [91] print.colorConverter*                             
 [92] print.compactPDF*                                 
 [93] print.condition                                   
 [94] print.connection                                  
 [95] print.data.frame                                  
 [96] print.default                                     
 [97] print.dendrogram*                                 
 [98] print.density*                                    
 [99] print.difftime                                    
[100] print.dist*                                       
[101] print.dummy_coef*                                 
[102] print.dummy_coef_list*                            
[103] print.ecdf*                                       
[104] print.eigen                                       
[105] print.factanal*                                   
[106] print.factor                                      
[107] print.family*                                     
[108] print.fileSnapshot*                               
[109] print.findLineNumResult*                          
[110] print.formula*                                    
[111] print.fseq*                                       
[112] print.ftable*                                     
[113] print.function                                    
[114] print.getAnywhere*                                
[115] print.glm*                                        
[116] print.hclust*                                     
[117] print.help_files_with_topic*                      
[118] print.hexmode                                     
[119] print.hsearch*                                    
[120] print.hsearch_db*                                 
[121] print.htest*                                      
[122] print.html*                                       
[123] print.html_dependency*                            
[124] print.infl*                                       
[125] print.integrate*                                  
[126] print.isoreg*                                     
[127] print.kmeans*                                     
[128] print.knitr_kable*                                
[129] print.libraryIQR                                  
[130] print.listof                                      
[131] print.lm*                                         
[132] print.loadings*                                   
[133] print.loess*                                      
[134] print.logLik*                                     
[135] print.ls_str*                                     
[136] print.medpolish*                                  
[137] print.mtable*                                     
[138] print.news_db*                                    
[139] print.nls*                                        
[140] print.no                                          
[141] print.noquote                                     
[142] print.numeric_version                             
[143] print.object_size*                                
[144] print.octmode                                     
[145] print.packageDescription*                         
[146] print.packageIQR*                                 
[147] print.packageInfo                                 
[148] print.packageStatus*                              
[149] print.pairwise.htest*                             
[150] print.pdf_doc*                                    
[151] print.pdf_fonts*                                  
[152] print.pdf_info*                                   
[153] print.person*                                     
[154] print.power.htest*                                
[155] print.ppr*                                        
[156] print.prcomp*                                     
[157] print.princomp*                                   
[158] print.proc_time                                   
[159] print.raster*                                     
[160] print.recordedplot*                               
[161] print.restart                                     
[162] print.rle                                         
[163] print.roman*                                      
[164] print.root_criterion*                             
[165] print.sessionInfo*                                
[166] print.shiny.tag*                                  
[167] print.shiny.tag.list*                             
[168] print.simple.list                                 
[169] print.smooth.spline*                              
[170] print.socket*                                     
[171] print.srcfile                                     
[172] print.srcref                                      
[173] print.stepfun*                                    
[174] print.stl*                                        
[175] print.subdir_tests*                               
[176] print.summarize_CRAN_check_status*                
[177] print.summary.aov*                                
[178] print.summary.aovlist*                            
[179] print.summary.ecdf*                               
[180] print.summary.glm*                                
[181] print.summary.lm*                                 
[182] print.summary.loess*                              
[183] print.summary.manova*                             
[184] print.summary.nls*                                
[185] print.summary.packageStatus*                      
[186] print.summary.ppr*                                
[187] print.summary.prcomp*                             
[188] print.summary.princomp*                           
[189] print.summary.table                               
[190] print.summary.warnings                            
[191] print.summaryDefault                              
[192] print.table                                       
[193] print.tables_aov*                                 
[194] print.terms*                                      
[195] print.ts*                                         
[196] print.tskernel*                                   
[197] print.tukeyline*                                  
[198] print.tukeysmooth*                                
[199] print.undoc*                                      
[200] print.vignette*                                   
[201] print.warnings                                    
[202] print.xfun_raw_string*                            
[203] print.xfun_strict_list*                           
[204] print.xgettext*                                   
[205] print.xngettext*                                  
[206] print.xtabs*                                      
see '?methods' for accessing help and source code

総称関数3

どのメソッドがディスパッチされたかは sloop::s3_dispatch() でわかる

# install.packages("sloop")
sloop::s3_dispatch(print(result))
   print.double
   print.numeric
=> print.default

総称関数4

print.default
function (x, digits = NULL, quote = TRUE, na.print = NULL, print.gap = NULL, 
    right = FALSE, max = NULL, useSource = TRUE, ...) 
{
    noOpt <- missing(digits) && missing(quote) && missing(na.print) && 
        missing(print.gap) && missing(right) && missing(max) && 
        missing(useSource) && missing(...)
    .Internal(print.default(x, digits, quote, na.print, print.gap, 
        right, max, useSource, noOpt))
}
<bytecode: 0x7f9d28d23a20>
<environment: namespace:base>

ようやく演算子のお話

冒頭の格言を思い出す

「Rのすべての関数はオブジェクトであり、すべてのオブジェクトは関数である。」

つまり

演算子も関数→関数名() という書き方ができるはず!

`+`(1, 2) # 1 + 1 と同じ
[1] 3
`<-`(a, 1 + 2) # a <- 1 + 2 と同じ
print(a)
[1] 3

※これはあくまで「演算子も関数であるというのを分かりやすくしているだけなので、Rでは普通こういう書き方はしません。(Lispっぽい書き方)」

ここからが本題

今日使うパッケージ

install.packages("pryr")
install.packages("lobstr")
install.packages("sloop")
install.packages("rlang")

注)dplyrの前身のplyrというパッケージがありましたがそれとは別物です

1 + 2 を読み解く

  • lobstr::ast() または pryr::ast() で構造を確認
  • どのような順序で関数が実行されているのかがわかる
lobstr::ast(1 + 2)
█─`+` 
├─1 
└─2 

ここでは何が起こっているのか

1 + 2
[1] 3

言い換えると、「`+`() 関数が実行されるときに何が起こっているのか」

これを知るために理解してきたいこと

  • 実行環境
  • `+()` 関数の中身

実行環境

環境とは

  • Rではオブジェクト(ここでは `+`() 関数 )が呼び出されたとき、それを探しに行きます。
  1. まず身近な相手にそれを持ってるか聞く。
  2. その人が持ってなかった時、じゃあ次はこの人に聞いてね、っていうのを教えてくれる
  3. それをずーっとたどっていって最後まで誰も持ってなかったらエラー。
(Rの)環境問題について その1。より

イメージは

Yet Another Introduction to tidyevalより

最初に聞く相手は .GlobalEnv

ls(pos = .GlobalEnv)
[1] "Q"        "a"        "print.no" "result"  

rlang::env_parent()
次の相手を教えてもらう

rlang::env_parent(.GlobalEnv)
<environment: package:stats>
attr(,"name")
[1] "package:stats"
attr(,"path")
[1] "/Library/Frameworks/R.framework/Versions/3.5/Resources/library/stats"

rlang::env_parents()
聞く相手の順番を教えてもらう

rlang::env_parents(.GlobalEnv)
[[1]] $ <env: package:stats>
[[2]] $ <env: package:graphics>
[[3]] $ <env: package:grDevices>
[[4]] $ <env: package:utils>
[[5]] $ <env: package:datasets>
[[6]] $ <env: package:methods>
[[7]] $ <env: Autoloads>
[[8]] $ <env: package:base>
[[9]] $ <env: empty>

search() でも良い

で、 `+`() は誰が持ってるの?

pryr::where("+")
<environment: base>

find() でも良い

ここまでで分かったこと

  • 1 + 2`+`(1, 2) を実行した結果である。
  • `+`() 関数はbaseパッケージが持っていて、そこから呼び出される

`+()` 関数の中身

`+`() 関数の中身を見ると…

`+`
function (e1, e2)  .Primitive("+")

.Primitive()

  • base パッケージの中でC言語の関数を呼び出すために使われる特殊な関数
  • .Interenal というのもあります。

.Primitive() その2

  • Rの関数は通常以下の3要素を持つ
    • body: 関数内部のRコード
    • formals: 引数の集まり
    • environment: 環境

      func_name <- (arg1, arg2, ...) {
        do something
      }

が、 .Primitive() の関数だけは例外

なぜならば、Rのコードが含まれないから

body(`+`)
NULL
formals(`+`)
NULL
environment(`+`)
NULL

C言語の関数の探し方

  • Rのソースコードから探す
    1. src/main/names.c からCで定義された関数を見つける
    2. Rのソースコードを見る
  • pryr::show_c_source() を使うと簡単

pryr::show_c_source()

> pryr::show_c_source(.Primitive("+"))
+ is implemented by do_arith with op = PLUSOP

C関数の中身は…

  • すいませんそこまで手が回りませんでした。。。
  • というかC言語にそんなに詳しくない。。。

まとめ

最初の目標

すごく単純なコードでも、また違って見えて面白いですね

result <- 1 + 2
print(result)
[1] 3

分かったこと

  • result <- 1 + 2`<- `(result, `+`(1, 2)) を実行した結果である。
  • `+`() 関数はbaseパッケージが (という環境) が持って、そこから呼び出される
  • ちなみに`<-()` 関数も同じ
  • `+`() 関数は .Primitive("+") というRのソースコード(C言語)の中で定義された関数が呼び出されたものだった

演算子

  • 普段何気なく使ってる演算子でもちゃんと理解しようとするとけっこう大変
  • でも(ある程度)分かっておくとパッケージ開発の時とか超便利
    →環境とかをちゃんと理解しておくと、パイプ演算子(%>%)のソースコードが読めるようになる

Rの内部を探る三種の神器

本資料について

参考文献1

参考文献2

R言語徹底解説 (原著: Advanced R)

Enjoy!