Если функция была определена, но еще не была вызвана, существуют ли формальные формы, не имеющие значений по умолчанию? Если да, то существуют ли они в среде выполнения, в среде, где находится определение функции, или где-то еще?
Если функция была определена, но еще не вызвана, а функции присвоено значение по умолчанию, существует ли это значение? Если да, то в какой среде он существует? Если выражение по умолчанию оценивается как константа, было ли присвоено этому значению формальное значение, которое должно быть перезаписано при вызове функции, если значение предоставлено? Если нет, то в какой среде это (фиксированное) значение по умолчанию находится между моментом определения и временем вызова функции?
После того, как функция была вызвана и фактические значения или значения по умолчанию были присвоены формальным формам, переданы в тело и, при необходимости, определены и / или оценены, продолжают ли формальные формы существовать? Если да, то в какой среде они тогда существуют?
Мне кажется ясным, о чем идет речь. По сути: если у вас есть что-то вроде fun <- function(x=2), существует ли x в какой-то среде? И вопрос в таких вариациях.
AFAIK, его не существует.
@HongOoi - вопрос Эндрю имеет смысл в контексте цитаты Джона Чемберса: «Чтобы понять вычисления в R, полезны два слогана: 1) Все, что существует, является объектом, и 2) Все, что происходит, - это вызов функции». Если все в R является объектом, формальные элементы функции также должны быть объектами. Поэтому разумно задавать вопросы об окружающей среде (ах), в которой они существуют.





Формы для функции существуют как объекты в среде функции после того, как экземпляр функции загружается в память при вызове. В Продвинутый R Хэдли Уикхэм называет эту среду среда исполнения. Доступ к ячейкам памяти объектов можно получить через pryr::address().
В качестве примера я буду использовать модифицированную версию кода, которую я ранее написал, чтобы проиллюстрировать ячейки памяти в функции makeVector() из второго задания по программированию для курса Джонса Хопкинса R программирование по coursera.org.
makeVector <- function(x = 200) {
library(pryr)
message(paste("Address of x argument is:",address(x)))
message(paste("Number of references to x is:",refs(x)))
m <- NULL
set <- function(y) {
x <<- y
message(paste("set() address of x is:",address(x)))
message(paste("Number of references to x is:",refs(x)))
m <<- NULL
}
get <- function() x
setmean <- function(mean) m <<- mean
getmean <- function() m
list(set = set, get = get,
setmean = setmean,
getmean = getmean)
}
Как указано выше, makeVector() - это объект S3, что означает, что мы можем получить доступ к объектам в его среде через геттеры и сеттеры, также известные как методы мутатора.
Мы можем загрузить экземпляр объекта makeVector() в память и запросить адрес и значение x с помощью следующего кода.
makeVector()$get()
... и результат:
> makeVector()$get()
Address of x argument is: 0x1103df4e0
Number of references to x is: 0
[1] 200
>
Как видно из выходных данных, x имеет место в памяти, но нет других объектов, которые содержат ссылки на него. Кроме того, для x было установлено значение по умолчанию вектора длины 1 со значением 200.
Я предоставляю подробный обзор объектов в среде makeVector() в своем ответе на Кэширование среднего значения вектора в R.
Что касается вопроса о том, как долго формальные элементы существуют в памяти, они существуют до тех пор, пока среда, созданная для хранения вызываемого экземпляра функции, находится в памяти. Поскольку сборщик мусора работает с объектами, у которых нет внешних ссылок, если экземпляр функции не сохраняется в объекте, он имеет право на сборку мусора, как только вызов функции возвращает результат в родительскую среду.
этот ответ очень ясен и восхитительно поучительно. Однако я все еще не уверен в некоторых деталях. (1) Является ли «среда выполнения функции после ее загрузки в память» тем же средой, что и среда выполнения? Или вызывающая или окружающая среда? Или что-то другое? Я воображал, что формальные значения и значения по умолчанию являются интерфейсом функции к внешнему миру и находятся в своей собственной «промежуточной» среде, но я уверен, что это неправильно. Почти уверен. (2) адрес x такой же, как у makeVector? И (продолжение)
(3) Происходит ли присвоение 200 0x1103df4e0, когда функция определена, когда она вызывается или в какое-то время между ними?
@andrewH - когда функция вызывается, R Evaluator создает новую среду для функции и инициализирует «объекты обещания» для каждого аргумента, перечисленного в формальном разделе функции. Эти объекты хранятся во вновь созданной среде для функции, которая является дочерней по отношению к среде, в которой была создана функция. Когда необходимо оценить аргументы, они будут оцениваться в среде, из которой пришел вызов. Любым аргументам, которым не присвоены значения в этом процессе, присваиваются значения по умолчанию (Программное обеспечение для анализа данных, Kindle Edition, расположение 809+).
@andrewH - (2) адрес (т.е. расположение в физической памяти) x отличается от адреса makeVector(). Это можно проверить, сохранив результат makeVector() в объекте, запустив на нем pryr::address() и сравнив этот адрес с адресом, возвращаемым $get(). (3) как указано выше, присвоение 200 происходит при вызове функции. Если я ответил на ваш вопрос, примите ответ.
повторю ваш первый ответ: так это среда, которую они называют средой исполнения, да? Извини, если я вбиваю это в землю. Я просто хочу быть уверенным, что могу связать то, что я узнаю от вас, с тем, что, как мне казалось, я узнал из «Advanced R» Хэдли. re ваш второй ответ: подойдет. Я прочитал ваш пост Caching the Mean. Очень красивая штука.
@andrewH - Да, это среда, которую Уикхэм называет средой выполнения в Глава окружения из Продвинутый R. Спасибо, что сообщили мне, что читаете это, чтобы я мог получить для вас правильную перекрестную ссылку. Кроме того, никаких извинений не требуется. Пожалуйста, задавайте столько дополнительных вопросов, сколько вам нужно, чтобы полностью понять концепции. Также спасибо за отзыв о моей исходной статье.
@LenGreski, стилистический вопрос: использование require в начале мало что даст: если он вернет FALSE, ваша функция будет продолжать работать без изменений (и не удастся с первым object not found). Есть ли причина (1) не проверять возвращаемое значение или (2) не использовать library? Или цель - более явный и самодокументированный код?
@ r2evans - Мое намерение было (2), но я обновлю код, включив проверку ошибок require() и вызов library().
Я не понимаю, чем ваш новый код лучше, чем просто library(pryr). Если require(pryr) возвращает F, ваш вызов library обязательно завершится неудачей; если он возвращает T, то library никогда не может быть вызван, но конечный результат тот же: пространство имен загружается и присоединяется к пути поиска и т. д.
@ r2evans - тут мозговая судорога немного, должна работать stop(), если require() дает сбой.
@ r2evans - прочитав Сообщение блога Yihui Xie о library() vs. require(), я согласен с тем, что library() более подходит, чем require(), хотя в документации R указано, что require() предназначен для использования в функциях R. Спасибо за то, что вы спрашивали меня об этом.
Не то чтобы я часами размышлял над этой темой, но ... я думаю, что единственное практическое использование require - это когда у вас есть два пути кода: один, когда доступен пакет, другой в противном случае, возможно, из-за скорости / эффективности, возможно, из-за дополнительных возможностей . В library второй путь жестко запрограммирован как stop. (И if (!require(...)) install.packages(), как правило, не следует использовать в продакшене, возможно, только в учебных / демонстрационных материалах.) Я уже цитировал этот пост, кстати, он хорошо написан.
Я понятия не имею, о чем вы спрашиваете