1. ホーム
  2. r

[解決済み] 関数のソースコードを見るにはどうしたらいいですか?

2022-03-15 03:53:24

質問

ある関数のソースコードを見て、その動作を確認したい。プロンプトに関数の名前を入力すれば、関数を表示できることは知っています。

> t
function (x) 
UseMethod("t")
<bytecode: 0x2332948>
<environment: namespace:base>

この場合、何をするかというと UseMethod("t") とは? 実際に使われているソースコードを見つけるには、例えば、どうすればいいのでしょう。 t(1:10) ?

と表示される場合とでは、違いがあるのでしょうか? UseMethodstandardGenericshowMethods と同様に with ?

> with
standardGeneric for "with" defined from package "base"

function (data, expr, ...) 
standardGeneric("with")
<bytecode: 0x102fb3fc0>
<environment: 0x102fab988>
Methods may be defined for arguments: data
Use  showMethods("with")  for currently available ones.

また、Rの関数が呼び出されているのはわかるのですが、その関数のソースコードが見つからないケースもあります。

> ts.union
function (..., dframe = FALSE) 
.cbind.ts(list(...), .makeNamesTs(...), dframe = dframe, union = TRUE)
<bytecode: 0x36fbf88>
<environment: namespace:stats>
> .cbindts
Error: object '.cbindts' not found
> .makeNamesTs
Error: object '.makeNamesTs' not found

のような関数を見つけるにはどうすればよいのでしょうか? .cbindts.makeNamesTs ?

また、Rのコードが少しあるけれど、ほとんどの作業は別の場所で行われているようなケースもあります。

> matrix
function (data = NA, nrow = 1, ncol = 1, byrow = FALSE, dimnames = NULL) 
{
    if (is.object(data) || !is.atomic(data)) 
        data <- as.vector(data)
    .Internal(matrix(data, nrow, ncol, byrow, dimnames, missing(nrow), 
        missing(ncol)))
}
<bytecode: 0x134bd10>
<environment: namespace:base>
> .Internal
function (call)  .Primitive(".Internal")
> .Primitive
function (name)  .Primitive(".Primitive")

を調べるにはどうしたらいいのでしょうか? .Primitive 関数は何をするのですか? 同様に、いくつかの関数は .C , .Call , .Fortran , .External または .Internal . これらのソースコードはどのように探せばよいのでしょうか?

どのように解決するのですか?

UseMethod("t") は、次のことを伝えています。 t() は、( S3 ) 汎用関数で、異なるオブジェクトクラス用のメソッドを持つ。

S3のメソッドディスパッチの仕組み

S3クラスについては methods 関数を使用すると、特定の汎用関数やクラスのメソッドを一覧表示できます。

> methods(t)
[1] t.data.frame t.default    t.ts*       

   Non-visible functions are asterisked
> methods(class="ts")
 [1] aggregate.ts     as.data.frame.ts cbind.ts*        cycle.ts*       
 [5] diffinv.ts*      diff.ts          kernapply.ts*    lines.ts        
 [9] monthplot.ts*    na.omit.ts*      Ops.ts*          plot.ts         
[13] print.ts         time.ts*         [<-.ts*          [.ts*           
[17] t.ts*            window<-.ts*     window.ts*      

   Non-visible functions are asterisked

可視でない関数にはアスタリスクが付けられますが、これはその関数がパッケージの名前空間からエクスポートされていないことを意味します。 その関数のソースコードは ::: 関数(例. stats:::t.ts を使用するか、または getAnywhere() . getAnywhere() は、関数がどのパッケージから来たものかを知る必要がないので便利です。

> getAnywhere(t.ts)
A single object matching ‘t.ts’ was found
It was found in the following places
  registered S3 method for t from namespace stats
  namespace:stats
with value

function (x) 
{
    cl <- oldClass(x)
    other <- !(cl %in% c("ts", "mts"))
    class(x) <- if (any(other)) 
        cl[other]
    attr(x, "tsp") <- NULL
    t(x)
}
<bytecode: 0x294e410>
<environment: namespace:stats>

S4方式のディスパッチシステム

S4方式は、S3方式に代わる新しい方式派遣方式です。以下は、S4関数の例です。

> library(Matrix)
Loading required package: lattice
> chol2inv
standardGeneric for "chol2inv" defined from package "base"

function (x, ...) 
standardGeneric("chol2inv")
<bytecode: 0x000000000eafd790>
<environment: 0x000000000eb06f10>
Methods may be defined for arguments: x
Use  showMethods("chol2inv")  for currently available ones.

出力はすでに多くの情報を提供しています。 standardGeneric はS4関数のインジケータである。定義されたS4メソッドを見るためのメソッドが提供されているのが便利です。

> showMethods(chol2inv)
Function: chol2inv (package base)
x="ANY"
x="CHMfactor"
x="denseMatrix"
x="diagonalMatrix"
x="dtrMatrix"
x="sparseMatrix"

getMethod は、あるメソッドのソースコードを見るために使うことができます。

> getMethod("chol2inv", "diagonalMatrix")
Method Definition:

function (x, ...) 
{
    chk.s(...)
    tcrossprod(solve(x))
}
<bytecode: 0x000000000ea2cc70>
<environment: namespace:Matrix>

Signatures:
        x               
target  "diagonalMatrix"
defined "diagonalMatrix"

また、各メソッドにもっと複雑なシグネチャを持つメソッドもあり、例えば

require(raster)
showMethods(extract)
Function: extract (package raster)
x="Raster", y="data.frame"
x="Raster", y="Extent"
x="Raster", y="matrix"
x="Raster", y="SpatialLines"
x="Raster", y="SpatialPoints"
x="Raster", y="SpatialPolygons"
x="Raster", y="vector"

これらのメソッドのソースコードを見るには、シグネチャ全体を指定する必要があります(例)。

getMethod("extract" , signature = c( x = "Raster" , y = "SpatialPolygons") )

部分署名を提供するだけでは十分ではありません。

getMethod("extract",signature="SpatialPolygons")
#Error in getMethod("extract", signature = "SpatialPolygons") : 
#  No method found for function "extract" and signature SpatialPolygons

未エクスポートの関数を呼び出す関数

の場合 ts.union , .cbindts.makeNamesTs からエクスポートされない関数です。 stats 名前空間を使用します。エクスポートされていない関数のソースコードは ::: 演算子または getAnywhere .

> stats:::.makeNamesTs
function (...) 
{
    l <- as.list(substitute(list(...)))[-1L]
    nm <- names(l)
    fixup <- if (is.null(nm)) 
        seq_along(l)
    else nm == ""
    dep <- sapply(l[fixup], function(x) deparse(x)[1L])
    if (is.null(nm)) 
        return(dep)
    if (any(fixup)) 
        nm[fixup] <- dep
    nm
}
<bytecode: 0x38140d0>
<environment: namespace:stats>

コンパイルされたコードを呼び出す関数

によって作成されたバイトコンパイルされたRコードを指しているのではないことに注意してください。 コンパイラ パッケージで提供されます。また <bytecode: 0x294e410> の行は、この関数がバイトコンパイルされていることを示し、Rのコマンドラインからソースを見ることができます。

を呼び出す関数は .C , .Call , .Fortran , .External , .Internal または .Primitive は、コンパイルされたコードのエントリーポイントを呼び出しているので、その機能を完全に理解したい場合は、コンパイルされたコードのソースを見る必要があります。 これは RのソースコードのGitHubミラーは、その手始めとして適切な場所です。この関数 pryr::show_c_source のGitHubページに直接移動できるので、便利なツールです。 .Internal.Primitive の呼び出しがあります。パッケージは .C , .Call , .Fortran および .External しかし .Internal または .Primitive なぜなら、これらはRインタプリタに組み込まれた関数を呼び出すために使用されるからです。

上記のいくつかの関数の呼び出しでは、コンパイルされた関数を参照するために文字列の代わりにオブジェクトを使用することがあります。そのような場合、オブジェクトはクラス "NativeSymbolInfo" , "RegisteredNativeSymbol" または "NativeSymbol" を作成し、そのオブジェクトを印刷すると、有用な情報が得られます。 例えば optim が呼び出す .External2(C_optimhess, res$par, fn1, gr1, con) (ただし、これは C_optimhess ではなく "C_optimhess" ). optim は stats パッケージに含まれているので、以下のように入力します。 stats:::C_optimhess をクリックすると、呼び出されたコンパイル済み関数の情報が表示されます。

パッケージ内のコンパイル済みコード

パッケージ内のコンパイルされたコードを表示したい場合は、パッケージのソースをダウンロード/アンパックする必要があります。インストールされたバイナリでは不十分です。パッケージのソースコードは、そのパッケージがもともとインストールされたのと同じ CRAN (または CRAN 互換) リポジトリから入手できます。が必要です。 download.packages() 関数は、パッケージのソースを取得することができます。

download.packages(pkgs = "Matrix", 
                  destdir = ".",
                  type = "source")

これは、Matrix パッケージのソースバージョンをダウンロードし、対応する .tar.gz ファイルをカレントディレクトリに保存します。コンパイルされた関数のソースコードは src ディレクトリに格納されます。解凍と紐付けのステップは、以下のディレクトリの外で行うことができます。 R または R を使用して untar() 関数を使用します。ダウンロードと展開のステップを1回の呼び出しにまとめることも可能です(この方法では、一度に1つのパッケージしかダウンロードと展開ができないことに注意してください)。

untar(download.packages(pkgs = "Matrix",
                        destdir = ".",
                        type = "source")[,2])

あるいは、パッケージの開発が公にホストされている場合 (たとえば ギットハブ , R-フォージ または RForge.net ) 、おそらくオンラインでソースコードを閲覧することができます。

ベースパッケージに含まれるコンパイル済みコード

ある種のパッケージは、基本パッケージとみなされます。これらのパッケージは R と一緒に出荷され、そのバージョンは R のバージョンにロックされています。 base , compiler , stats および utils . そのため、これらは上記のようにCRAN上で個別のダウンロード可能なパッケージとして利用することはできません。むしろ、それらはRのソースツリーの一部で /src/library/ . Rのソースにアクセスする方法については、次のセクションで説明します。

Rインタプリタに組み込まれたコンパイル済みコード

Rインタプリタに組み込まれたコードを表示したい場合は、Rのソースをダウンロード/アンパックする必要があります。 サブバージョンリポジトリ または Winston Changのgithubミラーサイト .

Uwe Liggesの Rニュース記事(PDF) (のソースコードの見方については、P.43が一般的な参考となります。 .Internal.Primitive 関数を使用することができます。 基本的な手順は、まず関数名を src/main/names.c の中にあるファイルから、Cエントリー名を探します。 src/main/* .