如何查看R语言中.Internal或.Primitive函数的源代码?

89

这两个选项都没有显示pnorm函数的源代码,

stats:::pnorm
getAnywhere(pnorm)  

我该如何查看pnorm函数的源代码?

sum
 (..., na.rm = FALSE)  .Primitive("sum")
.Primitive("sum")
function (..., na.rm = FALSE)  .Primitive("sum")
methods(sum)
no methods were found

那么,我如何查看sum函数的源代码呢?

3个回答

106
pnorm 的 R 源代码如下:
function (q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE) 
.Call(C_pnorm, q, mean, sd, lower.tail, log.p)

所以,从技术上讲,输入"pnorm"确实会显示源代码。然而,更有用的是:`pnorm`的核心是用C编写的,所以在前一个问题中的建议在R中查看源代码只是次要有用的(大部分集中在命名空间中隐藏的函数上)。
Uwe Ligges在R新闻文章中,访问源代码(第43页)是一个很好的参考资料。从那份文件中可以得到以下信息:
当查看R源代码时,有时会出现对以下函数之一的调用:.C().Call().Fortran().External().Internal().Primitive()。这些函数是调用编译代码中的入口点,如共享对象、静态库或动态链接库。因此,如果需要完全理解代码,就必须查看编译代码的源代码。 ... 第一步是在文件‘$R HOME/src/main/names.c’中查找入口点,如果调用的R函数是.Primitive().Internal()。下面的示例中就是这样做的,该示例实现了‘simple’ R函数sum()。 (重点是因为您询问的确切函数(sum)在Ligges的文章中有所涉及。)
根据您对代码的深入程度的要求,下载并解压源代码可能是值得的,正如Ligges所建议的那样(例如,您可以使用命令行工具如grep来搜索源代码)。如果只是进行一般的检查,您可以通过R的Subversion服务器Winston Chang的github镜像R-svn github镜像在线查看源代码(这里的链接是具体指向src/nmath/pnorm.c)。(要猜测正确的查找位置src/nmath/pnorm.c,需要对R源代码的结构有一定的了解。) meansum都是在summary.c中实现的。

1
它与 pnorm 不属于同一类别。请尝试使用 mean.default 进行 R 代码,并使用 https://github.com/wch/r-source/blob/trunk/src/main/summary.c 进行 C 代码。并且确保阅读上面链接的 Uwe Ligges 的文章! - Ben Bolker
1
仅作为对此答案的跟进:在C或Fortran中,函数名称可能需要特别小心。例如:我试图查找stl的源代码,它调用了这一行:z <- .Fortran(C_stl, x, n, as.integer(period), as.integer(s.window)。因此,我通过关键字C_stl搜索上面链接的Github镜像,但没有找到。然而,当我搜索stl时,有一个名为stl.f的文件,这就是我想要找的。要点是.c或.f文件名可能与被调用的函数名不完全相同。 - yuqli
我们什么时候应该使用 .Internal? - skan
1
@skan,我不理解这个问题。终端用户基本上不应使用.Internal(我使用R已有大约20年的经验,并从未在自己的代码中使用过它,至少我没有记得...)。如果您有更具体/聚焦的问题,请随时发布一个新问题... - Ben Bolker

40

我知道这篇文章已经超过2年了,但我认为这可能对一些浏览此问题的用户有用。

我基本上只是复制了我的答案到这个类似的问题,以便它可以对一些想要探索C源代码的R用户可能会有用。

  1. 首先,使用pryr,您可以使用show_c_source函数,在GitHub上搜索C源文件中相关的代码片段。适用于.Internal和.Primitive函数。

body(match.call)

# .Internal(match.call(definition, call, expand.dots))

pryr::show_c_source(.Internal(match.call(definition, call, expand.dots)))

这将带您到此页面,显示unique.c包含函数do_matchcall

我已经整理了这个制表符分隔的文件,基于names.c文件,并使用文件内查找来确定源代码的位置。有些函数具有特定于平台的文件,还有一些其他文件与相关源代码有关。但对于其余的部分,至少对于当前版本(3.1.2),映射相当成熟。


1
当我尝试查找system的C代码时,使用pryr::show_c_source(.Internal(system(x)))无法正常工作,出现了错误信息Error: Could not find entry for system - zhanxw

7
> methods(mean)
[1] mean.data.frame mean.Date       mean.default    mean.difftime   mean.IDate*    
[6] mean.POSIXct    mean.POSIXlt    mean.yearmon*   mean.yearqtr*  

   Non-visible functions are asterisked
> mean.default
function (x, trim = 0, na.rm = FALSE, ...) 
{
    if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {
        warning("argument is not numeric or logical: returning NA")
        return(NA_real_)
    }
    if (na.rm) 
        x <- x[!is.na(x)]
    if (!is.numeric(trim) || length(trim) != 1L) 
        stop("'trim' must be numeric of length one")
    n <- length(x)
    if (trim > 0 && n) {
        if (is.complex(x)) 
            stop("trimmed means are not defined for complex data")
        if (any(is.na(x))) 
            return(NA_real_)
        if (trim >= 0.5) 
            return(stats::median(x, na.rm = FALSE))
        lo <- floor(n * trim) + 1
        hi <- n + 1 - lo
        x <- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]
    }
    .Internal(mean(x))
}
<bytecode: 0x155ef58>
<environment: namespace:base>

1
这似乎并没有回答原帖关于 pnorm 的问题,但是他们在下面的评论中提到了 mean -- 需要注意的是,这也会落入底层的 C 代码中(请参见我下面的评论)。 - Ben Bolker
2
确实。而且“正确答案”就是你之前给出的……请阅读Uwe Ligges在RNews上的文章。 - IRTFM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接