Программирование

Как увидеть исходный код функции R и внутренние примитивы

Узнайте, как просматривать функции R, методы S3/S4 и внутренние примитивы. Используйте methods(), getAnywhere(), debug() и pryr::where() для анализа глубокого изучения.

Как просмотреть исходный код функции R

Я хочу изучить реализацию функций R, включая методы S3/S4 и внутренние примитивы. В частности:

  • Что означает UseMethod("t"), когда я набираю t в консоли, и как найти реальный метод, который выполняется для t(1:10)?
  • Как найти исходный код функций, объявленных как standardGeneric, например with?
  • Когда функция вызывает внутренние вспомогательные функции, такие как .cbindts или .makeNamesTs (например, ts.union), как я могу их найти?
  • Для функций, использующих .Internal, .Primitive, .C, .Call, .Fortran или .External, как узнать, что делают эти примитивы и где находится их реализация?

В общем, какие шаги и инструменты доступны в R для просмотра исходного кода функции, её методов и подлежащих примитивов, которые действительно выполняют работу?

t(1:10) — почему появляется UseMethod("t") и как узнать, какой метод будет выполнен?
Когда вы просто вводите t, вы видите верхнеуровневое определение

r
t <- function(x, ...) UseMethod("t")

Это S3‑генератор. UseMethod говорит R, что нужно выполнить диспетчеризацию к методу, имя которого строится из имени генератора и класса первого аргумента – например, t.numeric, t.data.frame и т.д.
Чтобы понять, какой метод будет вызван для t(1:10):

  1. Список доступных методов

    r
    methods(t)
    

    (Вы получите перечень всех функций t.*.)

  2. Посмотреть конкретный метод

    r
    getAnywhere(t.numeric)
    

    Или, если вам нужен только код метода, который будет вызван:

    r
    getAnywhere(t.class(1:10))
    

    (class(1:10) равно "numeric").

  3. Проверить код самого генератора – тело функции просто содержит вызов UseMethod, но вы всё‑таки можете посмотреть его через t.

Эти шаги работают для любого S3‑генератора. См. обсуждение в ответе на Stack Overflow о том, как просматривать исходный код функций.


Как просматривать исходный код функций, методов и примитивов

Задача Команда(ы) R Что показывает Источник
Генератор + S3‑метод methods(fun), getAnywhere(fun.method) Перечень методов; код конкретного метода Stack Overflow
Генератор + S4‑метод showMethods(fun), getMethod(fun, class) Подписи методов и их тело R‑Dev Guide
StandardGeneric (S4) getAnywhere("with"), getNamespace("stats") Тело функции; код диспетчеризации R‑Dev Guide
Внутренние вспомогательные функции (.cbindts, .makeNamesTs) getAnywhere(".cbindts"), getAnywhere(".makeNamesTs") Исходный код вспомогательных функций, обычно объявленных в одном файле SQL PeY
Примитивы/.Internal getAnywhere(".Internal") → ошибка; используйте ? для справки; смотрите исходный tarball R или GitHub Нет R‑кода; реализованы на C; найдите в исходниках R‑core R‑Documentation
.C, .Call, .Fortran, .External getAnywhere(".C") → нет R‑кода; посмотрите ?C для описания; найдите в C‑файлах (например, src/main/call.c) Интерфейс к внешним функциям; код находится в C‑исходниках R R‑core GitHub
Отладка/трассировка debug(fun), trace(fun, tracer=browser) Пошаговый просмотр R‑обёртки; видны вызовы примитивов Страницы справки R
Где реализован примитив pryr::where(fun) (из пакета pryr) Полный путь к C‑файлу, если он доступен Документация pryr

Пошаговый рабочий процесс

  1. Начните с того объекта, который вы ввели

    r
    myfun <- t
    
  2. Проверьте, является ли он примитивом

    r
    is.primitive(myfun)
    

    Если TRUE, посмотрите его справку (?t) или исходники R.

  3. Если не примитив, изучите тело

    r
    body(myfun)
    

    Для генератора вы увидите UseMethod.

  4. Узнайте, какой метод будет вызван

    r
    methods(myfun)
    

    Выберите подходящий и посмотрите его код через getAnywhere.

  5. Для S4‑генераторов

    r
    getNamespace("stats")$with
    getMethod("with", "data.frame")  # пример
    
  6. Для вспомогательных функций

    r
    getAnywhere(".cbindts")
    
  7. Для примитивов и внешних вызовов

    • Откройте справку (?C, ?Internal) для описания.
    • Найдите соответствующий C‑файл в исходниках R (например, Rcpp или репозиторий R‑core на GitHub) и ищите имя функции.
  8. Используйте trace или debug, чтобы увидеть цепочку вызовов

    r
    trace(t, tracer=browser)
    t(1:10)
    
  9. Если нужно полный R‑исходник пакета

    • Скачайте tarball пакета и посмотрите папку R/.
    • Или клонируйте репозиторий R‑core на GitHub, чтобы увидеть все файлы реализации.

Ключевые выводы

  • S3‑генераторы используют UseMethod; методы находите через methods() и getAnywhere().
  • S4‑генераторы (standardGeneric) находятся в пространстве имён; изучайте их с помощью getMethod() или getAnywhere().
  • Вспомогательные функции – обычные функции, часто с точкой в начале имени; ищите их через getAnywhere() или в исходниках.
  • Примитивы (.Primitive, .Internal) не имеют R‑кода; их поведение описано в C‑исходниках R‑core.
  • Внешние вызовы (.C, .Call, .Fortran, .External) – обёртки над скомпилированным кодом; используйте справку и исходники R для отслеживания.

Комбинируя methods(), getAnywhere(), debug(), trace() и исходники R (через GitHub или скачанный tarball), вы можете проследить любой R‑функционал – от высокоуровневой обёртки до компилируемого C‑кода.

Авторы
Проверено модерацией
Модерация