Next: , Previous: R Internal Structures, Up: Top



2 .Internal.Primitive

在R编译创建时,C代码编译进该系统可以看作“直接的”或通过 .Internal接口实现的。.Internal接口和.External 接口非常类似,除了在语法上。更准确地说,R维持着一个R函数名和 对应的会被调用的C函数的对应表。在习惯上,这些C函数以do_开始并且 返回SEXP。通过这个对应表(文件src/main/names.c内的R_FunTab), 我们可以指定一个函数需要或运行几个参数,在调用前参数是否需要赋值,和是否是 “内部”函数以致需要通过.Internal接口访问或者如.Primitive一样 直接方法且在R里面答应。

R的功能性还可以通过提供对应的C代码然后 加到该函数对应表中来扩充。

通常,这类函数使用 .Internal() 接口,因为这样做比较 安全,特别是允许透明地处理命名的和默认的参数。例如, axis 如下定义

     axis <- function(side, at = NULL, labels = NULL, ...)
         .Internal(axis(side, at, labels, ...))

但是,出于便利和效率考虑(还因为在一个函数闭包里面用.Internal 接口有一些限制),有些函数可以直接访问。注意, 这些函数不用 R 代码,因此 和通常的解释型函数差别很大。特别是, argsformalsbody 对这些对象返回 NULL,并且参数匹配完全基于位置 (空位置的会被抛弃)。

这些 “原始” 函数的列表常常会改变: 现在,它包括如下一些函数。

  1. “专用函数”(Special functions)实际上是语言元素,但以 “原始”函数的形式在 R 中存在:
              {       (         if     for      while  repeat  break  next
              return  function  quote  on.exit
         
  2. 用于子集,赋值,算术和逻辑运算的基本操作符(也就是函数,但通常不被foo(a, b, ...)这样的函数看待)。 这些是如下的1-,2-,和N-参数函数:
                             [    [[    $    @
              <-   <<-  =    [<-  [[<-  $<-
              
              +    -    *    /     ^    %%   %*%  %/%
              <    <=   ==   !=    >=   >
              |    ||   &    &&    !
         
  3. “底层”(Low level)的 0- 和 1-参数函数属于如下几组函数中的一种:
    1. 含有单个参数的数学函数,也就是,
                     sign    abs
                     floor   ceiling  trunc
                     
                     sqrt    exp
                     cos     sin      tan
                     acos    asin     atan
                     cosh    sinh     tanh
                     acosh   asinh    atanh
                     
                     cumsum  cumprod cummax  cummin
                     
                     Im      Re     Arg     Conj     Mod
                

      注意,R 函数 log有个可选的命名参数 base,因此定义如下,

                     log <- function(x, base = exp(1)) {
                       if(missing(base))
                         .Internal(log(x))
                       else
                         .Internal(log(x, base))
                     }
                

      这样保证了 log(x = pi, base = 2)log(base = 2, x = pi)完全一样。

    2. 函数很少在“编程过程”外使用(即,总是在其它函数内部使用), 如
                     nargs        missing
                     interactive  is.xxx
                     .Primitive   .Internal
                     globalenv    baseenv     emptyenv     pos.to.env
                     unclass
                     seq_along    seq_len
                

      (其中xxx表示27个不同的概念,如 function, vector, numeric等等,但不是 is.loaded)。

    3. 编程和会话管理功能
                     debug    undebug browser  proc.time  gc.time
                
  4. 基本的替换和提取功能
              length      length<-
              class       class<-
              oldClass    oldCLass<-
              attr        attr<-
              attributes  attributes<-
              names       names<-
              dim         dim<-
              dimnames    dimnames<-
                          environment<-
                          levels<-
         

    注意,优化 NAMED = 1 仅仅在原始函数中有效 (因为.Internal的闭包会在参数中设置NAMED = 2),因此 替换函数必须是原始函数(如果可能)以避免拷贝(至少在它们默认的方法中)。

  5. 出于效率考虑,下面一些 N-参数的函数是“原始”函数:
              :          ~          c           list
              call       as.call    as.character
              expression substitute as.environment
              UseMethod  invisible  standardGeneric
              .C         .Fortran   .Call       .External
              .Call.graphics        .External.graphics
              .subset    .subset2   .primTrace  .primUntrace
              tracemem   retracemem untracemem
              rep        seq.int
         

    repseq.int 管理它们自己的参数匹配并且以标准方式工作。