Как объявить метод S3 по умолчанию для загруженной среды? - PullRequest
1 голос
/ 01 апреля 2020

В пакете я хотел бы назвать метод S3 «компактным» для объекта foobar.

Поэтому в моем пакете должна быть функция compact.foobar вместе с функцией compact само по себе:

compact = function(x, ...){
    UseMethod("compact", x)
}

Однако это последнее будет конфликтовать с purrr::compact.

Я мог бы по умолчанию использовать метод purrr (compact.default = purrr::compact или, возможно, compact.list = purrr::compact) , но это не имело бы никакого смысла, если бы пользователь не загружал purrr.

Как я могу использовать по умолчанию мой метод для загруженной версии compact в пользовательской среде? (так что он использует purrr::compact, любую другую объявленную функцию compact или не выполняет отсутствующую функцию)

1 Ответ

1 голос
/ 02 апреля 2020

К сожалению, S3 плохо справляется с этой ситуацией. Вы должны искать подходящие функции вручную. Следующие работы, более или менее:

get_defined_function = function (name) {
    matches = getAnywhere(name)
    # Filter out invisible objects and duplicates
    objs = matches$objs[matches$visible & ! matches$dups]
    # Filter out non-function objects
    funs = objs[vapply(objs, is.function, logical(1L))]
    # Filter out function defined in own package.
    envs = lapply(funs, environment)
    funs = funs[! vapply(envs, identical, logical(1L), topenv())]
    funs[1L][[1L]] # Return `NULL` if no function exists.
}
compact.default = function (...) {
    # Maybe add error handling for functions not found.
    get_defined_function('compact')(...)
}

Использует getAnywhere, чтобы найти все объекты с именем compact, о которых R знает. Затем он отфильтровывает те, которые не видны, потому что они не находятся внутри прикрепленных пакетов, и те, которые являются дубликатами (это, вероятно, избыточно, но мы все равно делаем это).

Далее, он отфильтровывает все, что не является функция. И, наконец, он отфильтровывает compact S3 generi c, который определяет наш собственный пакет. Для этого он сравнивает среду каждой функции со средой пакета (заданной topenv()).

Это должно сработать, но у него нет правила, какую функцию предпочитать, если существует несколько функций с одинаковым именем определяется в разных местах (сначала он выбирает произвольную единицу), а также не проверяет соответствие сигнатуры функции (это сложно сделать в R, поскольку вызов функции и сопоставление параметров очень гибкие).

...