Ответ 1
Несмотря на мой комментарий, это грубоватый способ проверить это:
rm(.Random.seed) # if it already exists
makeActiveBinding('.Random.seed',
function () stop('Something touched my seed', call. = FALSE),
globalenv())
Это сделает .Random.seed
в активную привязку , которая вызывает ошибку при ее касании.
Это работает, но очень разрушительно. Heres более мягкий вариант. Он имеет несколько интересных особенностей:
- Он позволяет включать и отключать отладку
.Random.seed
- Он поддерживает получение и установку семени
- Он регистрирует вызов, но не останавливает выполнение
- Он поддерживает "белый список" вызовов верхнего уровня, которые не должны регистрироваться
С этим вы можете написать следующий код, например:
# Ignore calls coming from sample.int
> debug_random_seed(ignore = sample.int)
> sample(5)
Getting .Random.seed
Called from sample(5)
Setting .Random.seed
Called from sample(5)
[1] 3 5 4 1 2
> sample.int(5)
[1] 5 1 2 4 3
> undebug_random_seed()
> sample(5)
[1] 2 1 5 3 4
Вот реализация во всей красе:
debug_random_seed = local({
function (ignore) {
seed_scope = parent.env(environment())
if (is.function(ignore)) ignore = list(ignore)
if (exists('.Random.seed', globalenv())) {
if (bindingIsActive('.Random.seed', globalenv())) {
warning('.Random.seed is already being debugged')
return(invisible())
}
} else {
set.seed(NULL)
}
# Save existing seed before deleting
assign('random_seed', .Random.seed, seed_scope)
rm(.Random.seed, envir = globalenv())
debug_seed = function (new_value) {
if (sys.nframe() > 1 &&
! any(vapply(ignore, identical, logical(1), sys.function(1)))
) {
if (missing(new_value)) {
message('Getting .Random.seed')
} else {
message('Setting .Random.seed')
}
message('Called from ', deparse(sys.call(1)))
}
if (! missing(new_value)) {
assign('random_seed', new_value, seed_scope)
}
random_seed
}
makeActiveBinding('.Random.seed', debug_seed, globalenv())
}
})
undebug_random_seed = function () {
if (! (exists('.Random.seed', globalenv()) &&
bindingIsActive('.Random.seed', globalenv()))) {
warning('.Random.seed is not being debugged')
return(invisible())
}
seed = suppressMessages(.Random.seed)
rm('.Random.seed', envir = globalenv())
assign('.Random.seed', seed, globalenv())
}
Некоторые примечания о коде:
- Функция
debug_random_seed
определена внутри собственной частной среды. Эта среда обозначается символомseed_scope
в коде. Это предотвращает утечку частной переменнойrandom_seed
в глобальную среду. - Функция защищает проверку того, включена ли отладка. Может быть, Overkill.
- Отладочная информация выводится только при посещении семпла в вызове функции. Если пользователь проверяет
.Random.seed
непосредственно на консоли R, никаких протоколов не происходит.