Scoping - функция счетчика работает нормально, но не в пользовательском пакете - PullRequest
0 голосов
/ 20 мая 2018

У меня есть функция счетчика, которую я люблю оборачивать вокруг другой функции («забавы»), чтобы отслеживать, сколько раз я ее вызывал.Я отслеживаю вызовы, создавая новую среду "counter.env", если она еще не существует, и сохраняя счетчик там.

counter <- function(fun) {
if (!exists("counter.env", envir = .GlobalEnv)) {
counter.env <<- new.env(parent = globalenv())
assign("i", 0, envir = counter.env)
}
function(...) {
local(i <- i+1, env = counter.env)
fun(...)
}
}

Также у меня есть функция "get_calls", которая простопозвоните, чтобы получить счет из окружающей среды.Я хотел бы, чтобы он запускал 0 в случае, если пользователь вызывает его до фактической функции, которую он вызывает, по любой причине, по которой он это сделает.

get_calls <- function() {
if (!exists("counter.env", envir = .GlobalEnv)) {
counter.env <<- new.env(parent = .GlobalEnv)
assign("i", 0, envir = counter.env)
}
get("i", envir = counter.env)
}

Наконец, давайте скажем, что функция яwrapping - это функция с собственным аргументом "fun (arg1)".Так что я заверну это.

count.and.call <- counter(fun)

И я называю это так:

count.and.call(arg1) 

Сразу же создается "counter.env" в моей глобальной среде, и я могу вернуть вызов с помощью get_calls.

Теперь барабанная дробь Когда я помещаю эти функции в пакет, собираю пакет и запускаю

count.and.call(arg1)

, counter.env не создается в глобальном env.и это показывает

error in eval(quote(i <- i + 1), counter.env) : 
object 'counter.env' not found

Моя непосредственная задача состоит в том, чтобы починить мой счетчик, что, вероятно, связано с определением объема среды.

Однако я также не уверен, использовал ли я лучшеепрактики для моей контр-функции, если да, могу ли я получить совет?

Ответы [ 2 ]

0 голосов
/ 20 мая 2018

Еще один способ сделать это - использовать замыкания.Например:

countingFun <- function(fun) {
  count <- 0
  function(x) {
    count <<- count + 1
    fun(x)
  }
}

count <- function(fun) {
  environment(fun)$count
}

Сохраняет счет в среде функции, которая создается автоматически и содержит все переменные, локальные для вызова countingFun.Затем вы можете сделать

myMean <- countingFun(mean)
mySd   <- countingFun(sd)
myMean(x)
mySd(x)
myMean(x)
count(myMean)  # 2
count(mySd)    # 1

Возможно, вы захотите добавить некоторую проверку ошибок в count, чтобы убедиться, что она не вызывается для функции, которая не считается.

0 голосов
/ 20 мая 2018

Лучшая практика заключается в том, что ваш пакет не должен вмешиваться в глобальную среду.Если вы хотите сохранить состояние, создайте для него среду в пространстве имен вашего пакета.Вам даже не нужно указывать местоположение самостоятельно, по умолчанию это происходит автоматически.

В исходном файле:

counter.env <- new.env()

# this gets run every time your package is loaded
.onLoad <- function(libname, pkgname)
{
    counter.env$i <- 0
}

counter <- function(fun)
{
    # do stuff...
   counter.env$i <- counter.env$i + 1
}

reset_counter <- function()
{
    counter.env$i <- 0
}

# necessary if you want the user to see the counter and you don't export counter.env
get_counter <- function()
{
    counter.env$i
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...