Подтвердить что ты не робот

Ленькая оценка в R - назначается пострадавшим?

Я прочитал этот основной вопрос о переименовании объектов и @Shane, чтобы ответить на него, указав на ленивую оценку. Теперь я задаюсь вопросом, оценивается ли assign лениво. Также как здесь:

assign("someNewName",someOldObject)
rm(someOldObject)

Причина, по которой я удивляюсь, это следующий прецедент: предположим, что у меня есть объекты 10K + R, каждый из которых имеет два атрибута, называемых originalName и additionalName. Теперь я хочу написать функцию, которая может позволить пользователю переключиться с одного имени на другое без потери этих двух атрибутов. Примерно так...

EDIT: на основе ввода @Hadley я изменил свой код.

switchObjectName <- function(x) {
  n1 <- attributes(x)$originalName
  n2 <- attributes(x)$additionalName
  objName <- deparse(substitute(x))
  if(objName == n1) {
    delayedAssign(n2,x,assign.env=.GlobalEnv)
  } else {
    delayedAssign(n1,x,assign.env=.GlobalEnv)
  }
  rm(list=c(objName),envir=.GlobalEnv)    
}

это работает хорошо, но мне было довольно сложно получить инструкцию rm. Я пробовал rm(objName,envir=.GlobalEnv), но не смог заставить его работать, хотя objName определенно является символом, потому что это результат deparse(substitute(x).

4b9b3361

Ответ 1

Язык R обычно имеет семантику значений. Назначение x <- y означает, что x и y будут независимыми копиями одного и того же объекта (обновления на y и x будут независимыми). Наивная реализация x <- y всегда выделяет память для x и полностью копирует y в нее. Вместо этого GNU-R использует механизм копирования на запись, он откладывает копию до тех пор, пока не произойдет обновление, что экономит время памяти/времени выполнения, если это не произойдет. Пользователи R не должны знать об этой оптимизации, они полностью прозрачны (за исключением некоторых редких случаев, таких как ошибки из памяти). Этот механизм применяется к присваиванию, обозначенному как x <- y и assign("x", y) в равной степени.

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

delayedAssign - это низкоуровневая функция, видимая для пользователей/программистов R, но она действительно используется только для ленивой загрузки пакетов и не нужна в пользовательских программах. delayedAssign позволяет указать выражение для вычисления значения переменной; вычисление будет происходить лениво, только если /, когда переменная читается в первый раз.

Итак, чтобы ответить на вопрос, назначение в R всегда "лениво" в том, что используется механизм копирования на запись. Вычисление правой части присваивания может быть также ленивым (с использованием delayedAssign), но это не должно быть необходимо/использовано пользовательскими программами.

Я думаю, что для "переименования" переменных нет необходимости использовать delayedAssign (потому что правая сторона не вычисляется). Это только усложняет ситуацию, и, скорее всего, из-за бухгалтерии delayedAssign будет накладные расходы на производительность. Я бы просто использовал обычное задание, если мне пришлось переименовывать переменные.

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

Упомянув механизм копирования на запись, с текущей реализацией в GNU-R, любое из описанных решений потенциально может вызвать копирование памяти, которое не было бы необходимо, если бы переменные не были переименованы. Невозможно избежать этого на уровне R.