[英]Understanding how .Internal C functions are handled in R
我想知道是否有人可以向我說明R如何從控制台提示符下鍵入的R命令執行C
調用。 我對R
對a)函數參數和b)函數調用本身的處理特別感到困惑。
我們舉一個例子,在這種情況下是set.seed()
。 想知道它是如何工作的我在提示符下輸入名稱,獲取源代碼( 在這里查看更多內容 ),看看最終有一個.Internal(set.seed(seed, i.knd, normal.kind)
,所以盡職盡責在/src/names.c
的.Internals
部分查找相關的函數名,找到它叫做do_setseed
並在RNG.c
,這導致我...
SEXP attribute_hidden do_setseed (SEXP call, SEXP op, SEXP args, SEXP env)
{
SEXP skind, nkind;
int seed;
checkArity(op, args);
if(!isNull(CAR(args))) {
seed = asInteger(CAR(args));
if (seed == NA_INTEGER)
error(_("supplied seed is not a valid integer"));
} else seed = TimeToSeed();
skind = CADR(args);
nkind = CADDR(args);
//...
//DO RNG here
//...
return R_NilValue;
}
CAR
, CADR
, CADDR
? 我的研究讓我相信它們是一個受Lisp
影響的有關列表的構造,但除此之外,我不明白這些函數的作用或為什么需要它們 。 checkArity()
什么作用? SEXP args
似乎是自解釋的,但這是函數調用中傳遞的參數列表嗎? SEXP op
代表什么? 我認為這意味着運算符(如二進制函數,如+
),但那么SEXP call
是什么? 是否有人能夠流經我打字時發生的事情
set.seed(1)
在R控制台提示符下,直到定義skind
和nkind
的點? 我發現我無法很好地理解這個級別的源代碼以及從解釋器到C函數的路徑。
CAR
和CDR
是您訪問pairlist對象的方式,如R語言定義的 2.1.11節所述 。 CAR
包含第一個元素, CDR
包含其余元素。 編寫R擴展的第5.10.2節給出了一個例子:
#include <R.h>
#include <Rinternals.h>
SEXP convolveE(SEXP args)
{
int i, j, na, nb, nab;
double *xa, *xb, *xab;
SEXP a, b, ab;
a = PROTECT(coerceVector(CADR(args), REALSXP));
b = PROTECT(coerceVector(CADDR(args), REALSXP));
...
}
/* The macros: */
first = CADR(args);
second = CADDR(args);
third = CADDDR(args);
fourth = CAD4R(args);
/* provide convenient ways to access the first four arguments.
* More generally we can use the CDR and CAR macros as in: */
args = CDR(args); a = CAR(args);
args = CDR(args); b = CAR(args);
還有一個TAG
宏來訪問給實際參數的名稱。
checkArity
確保傳遞給函數的參數數量是正確的。 args
是傳遞給函數的實際參數。 op
是偏移指針“用於處理多個R函數的C函數”(引自src/main/names.c
,其中還包含顯示每個函數的偏移和arity的表)。
例如, do_colsum
處理col/rowSums
和col/rowMeans
。
/* Table of .Internal(.) and .Primitive(.) R functions
* ===== ========= ==========
* Each entry is a line with
*
* printname c-entry offset eval arity pp-kind precedence rightassoc
* --------- ------- ------ ---- ----- ------- ---------- ----------
{"colSums", do_colsum, 0, 11, 4, {PP_FUNCALL, PREC_FN, 0}},
{"colMeans", do_colsum, 1, 11, 4, {PP_FUNCALL, PREC_FN, 0}},
{"rowSums", do_colsum, 2, 11, 4, {PP_FUNCALL, PREC_FN, 0}},
{"rowMeans", do_colsum, 3, 11, 4, {PP_FUNCALL, PREC_FN, 0}},
請注意,上表中的arity
為4,因為(即使rowSums
等只有3個參數) do_colsum
有4個,您可以從rowSums
的.Internal
調用中rowSums
:
> rowSums
function (x, na.rm = FALSE, dims = 1L)
{
if (is.data.frame(x))
x <- as.matrix(x)
if (!is.array(x) || length(dn <- dim(x)) < 2L)
stop("'x' must be an array of at least two dimensions")
if (dims < 1L || dims > length(dn) - 1L)
stop("invalid 'dims'")
p <- prod(dn[-(1L:dims)])
dn <- dn[1L:dims]
z <- if (is.complex(x))
.Internal(rowSums(Re(x), prod(dn), p, na.rm)) + (0+1i) *
.Internal(rowSums(Im(x), prod(dn), p, na.rm))
else .Internal(rowSums(x, prod(dn), p, na.rm))
if (length(dn) > 1L) {
dim(z) <- dn
dimnames(z) <- dimnames(x)[1L:dims]
}
else names(z) <- dimnames(x)[[1L]]
z
}
基本的C級pairlist提取功能是CAR
和CDR
。 (Pairlists與列表非常相似,但是作為鏈表實現,並在內部用於參數列表)。 它們具有簡單的R等價物: x[[1]]
和x[-1]
。 R還提供了兩者的許多組合:
CAAR(x) = CAR(CAR(x))
等於x[[1]][[1]]
CADR(x) = CAR(CDR(x))
,相當於x[-1][[1]]
,即x[[2]]
CADDR(x) = CAR(CDR(CDR(x))
相當於x[-1][-1][[1]]
,即x[[3]]
與訪問列表的第n個元素O(1)
不同,訪問pairlist的第n個元素是O(n)
操作。 這就是為什么沒有更好的功能來訪問pairlist的第n個元素。
內部/原始函數不按名稱進行匹配,它們僅使用位置匹配,這就是為什么它們可以使用這個簡單的系統來提取參數。
接下來,您需要了解C函數的參數是什么。 我不確定這些文件在哪里記錄,所以我可能不完全正確的結構,但我應該是一般的部分:
call
:完成調用,可能由match.call()
捕獲
op
:從R調用的.Internal函數的索引。這是必需的,因為從.Internal函數到C函數有多對一的映射。 (例如, do_summary
實現sum,mean,min,max和prod)。 該數字是names.c
的第三個條目 - 對於do_setseed
,它始終為0,因此從未使用過
args
:提供給函數的參數的一對列表。
env
:調用函數的環境。
checkArity
是一個調用Rf_checkArityCall
的宏,它基本上查找參數的數量( names.c
的第五列是arity)並確保提供的數字匹配。 你必須在C中完成相當多的宏和函數才能看到正在發生的事情 - 擁有一個你可以通過的R源的本地副本是非常有幫助的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.