Как увидеть исходный код функции 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, вы видите верхнеуровневое определение
t <- function(x, ...) UseMethod("t")
Это S3‑генератор. UseMethod говорит R, что нужно выполнить диспетчеризацию к методу, имя которого строится из имени генератора и класса первого аргумента – например, t.numeric, t.data.frame и т.д.
Чтобы понять, какой метод будет вызван для t(1:10):
-
Список доступных методов
rmethods(t)(Вы получите перечень всех функций
t.*.) -
Посмотреть конкретный метод
rgetAnywhere(t.numeric)Или, если вам нужен только код метода, который будет вызван:
rgetAnywhere(t.class(1:10))(
class(1:10)равно"numeric"). -
Проверить код самого генератора – тело функции просто содержит вызов
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 |
Пошаговый рабочий процесс
-
Начните с того объекта, который вы ввели
rmyfun <- t -
Проверьте, является ли он примитивом
ris.primitive(myfun)Если
TRUE, посмотрите его справку (?t) или исходники R. -
Если не примитив, изучите тело
rbody(myfun)Для генератора вы увидите
UseMethod. -
Узнайте, какой метод будет вызван
rmethods(myfun)Выберите подходящий и посмотрите его код через
getAnywhere. -
Для S4‑генераторов
rgetNamespace("stats")$with getMethod("with", "data.frame") # пример -
Для вспомогательных функций
rgetAnywhere(".cbindts") -
Для примитивов и внешних вызовов
- Откройте справку (
?C,?Internal) для описания. - Найдите соответствующий C‑файл в исходниках R (например,
Rcppили репозиторий R‑core на GitHub) и ищите имя функции.
- Откройте справку (
-
Используйте
traceилиdebug, чтобы увидеть цепочку вызововrtrace(t, tracer=browser) t(1:10) -
Если нужно полный R‑исходник пакета
- Скачайте tarball пакета и посмотрите папку
R/. - Или клонируйте репозиторий R‑core на GitHub, чтобы увидеть все файлы реализации.
- Скачайте tarball пакета и посмотрите папку
Ключевые выводы
- 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‑кода.