Вызов print(ls.str()) в функции влияет на поведение rep

Начните новый сеанс R с пустой средой. Напишите серию функций с параметром, который будет использоваться в качестве значения параметра times при вызове rep().

f <- function(n) {
  rep("hello", times = n)
}
f(x)

Можно ожидать, что это потерпит неудачу, и действительно получается:

# Error in f(x) : object 'x' not found

Немного изменим функцию:

f2 <- function(n) {
  ls.str()
  rep("hello", times = n)
}

f2(x)

Как и ожидалось, это все еще терпит неудачу:

# Error in f2(x) : object 'x' not found

Измените еще немного (чтобы увидеть среду в консоли):

f3 <- function(n) {
  print(ls.str())
  rep("hello", times = n)
}

f3(x)

Я все еще ожидаю неудачи, но вместо этого получаю:

## n : <missing>
## [1] "hello"

Как будто вызов print() заставляет rep работать, как если бы times было установлено на 1.


r rep
person Homer White    schedule 18.09.2017    source источник


Ответы (3)


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

f3 <- function(n) {
  try(get("n", environment(), inherits=FALSE))
  rep("hello", times = n)
}
f3(x)
## Error in get("n", environment(), inherits = FALSE) : object 'x' not found
## [1] "hello"

Следующее носит предположительный характер и основано на поверхностном изучении источника do_rep. get запускает оценку промиса, но, не найдя «отсутствующий» символ, кажется, что промис частично не оценивается. rep, будучи примитивом, затем пытается работать с n, не понимая, что это частично оцененное обещание, и в основном это неявно приводит к предположению, что «n == 1».

Кроме того, это показывает, что обещание находится в странном состоянии (чтобы увидеть его, нужно использовать browser/debug):

f3a <- function(n) {
  try(get("n", environment(), inherits=FALSE))
  browser()
  rep("hello", times = n)
}
f3a(x)
## Error in get("n", environment(), inherits = FALSE) : object 'x' not found
## Called from: f3a(x)
# Browse[1]> (n)
## Error: object 'x' not found
## In addition: Warning message:
## restarting interrupted promise evaluation 
## Browse[1]> c
## [1] "hello"
person BrodieG    schedule 18.09.2017
comment
Я уже могу воспроизвести код только с rep строкой, try(get(…)) не нужно. На самом деле, я думаю, что do_rep просто неправильно сопоставляет свои ручные аргументы, отказывается от несуществующего обещания и делает вид, что ни один аргумент, кроме x, не установлен. Дело в «частично неоцененном» обещании — отвлекающий маневр. - person Konrad Rudolph; 19.09.2017
comment
@KonradRudolph Я не слежу. f3a <- function(n) rep("hello", times = n); f3a(x) не воспроизводит это. - person Roland; 19.09.2017
comment
@ Роланд Арг, действительно. Но f3a() знает. - person Konrad Rudolph; 19.09.2017

Сегодня я получил сообщение о том, что ошибка была исправлена ​​в R-devel и R-патч.

Проблема заключалась в том, что тест на отсутствие в исходниках R не учитывал случай прерванного оценка обещаний. Исправление внесено Люком Тирни и может можно увидеть на GitHub.

person Homer White    schedule 20.09.2017
comment
Да! Принятие сейчас (все еще относительно новое для проверки Stack Exchange ...) - person Homer White; 20.09.2017
comment
@BrodieG, я ни за что не собирался входить в список R-devel, сообщая об ошибке, не подтвердив сначала Big Dogs. Отсюда и мой пост здесь. - person Homer White; 20.09.2017

f4 <- function(n) {
  print('test')
  print(ls.str())
  print('end test')
  rep("hello", times = n)
}
f4(x)

## [1] "test"
## n : <missing>
## [1] "end test"
## [1] "hello"

В print.ls_str что-то есть, из теста Фрэнка в чате следующий код демонстрирует ту же проблему:

f6 <- function(n) {
  z = tryCatch(get("n", new.env(), mode = "any"), error = function(e) e)
  rep("A", n)
}

Немного покопавшись в исходниках R, я нашел следующий код

#     define GET_VALUE(rval)                      \
    /* We need to evaluate if it is a promise */  \ 
    if (TYPEOF(rval) == PROMSXP) {                \
        PROTECT(rval);                            \
        rval = eval(rval, genv);                  \
        UNPROTECT(1);                             \
    }                                             \
                                                  \
    if (!ISNULL(rval) && NAMED(rval) == 0)        \
        SET_NAMED(rval, 1)


    GET_VALUE(rval);
    break;


    case 2: // get0(.)
    if (rval == R_UnboundValue)
        return CAD4R(args);// i.e.  value_if_not_exists
    GET_VALUE(rval);
    break;
    }
    return rval;
}
#undef GET_VALUE

Я очень удивлен, что эта компиляция правильно, насколько я помню (мой C сильно отстает) #define не допускает пробелов между # и определением.

Покопавшись в этом, я ошибаюсь из gcc doc< /а>:

Также допускаются пробелы до и после `#'.

Так что, вероятно, в этой части кода что-то есть, но мне не по силам точно определить, что именно.

person Tensibai    schedule 18.09.2017
comment
Я не уверен, что вы подразумеваете под пустым (NULL?), но я не думаю, что это делает что-то подобное. Причина в том, что f4 ‹- function(n) { print(ls.str()) replace(n) } работает как положено. Например, f4(x) возвращает x. - person Homer White; 18.09.2017
comment
Я думаю, что ваша попытка объяснения слишком проста. Если я использую f3 <- function(n) { print(ls.str()); print(n); rep("hello", times = n) }, я получаю интересное предупреждение: In print(n) : restarting interrupted promise evaluation. Итак, по-видимому, print.ls.str делает что-то странное с обещанием. - person Roland; 18.09.2017
comment
@Roland действительно, копает немного больше, так как f6 <- function(n) { z = tryCatch(get("n", new.env(), mode = "any"), error = function(e) e); rep("A", n) } демонстрирует такое же поведение (tryCatch исходит из print.ls_str (спасибо Фрэнку за заголовок в этой части) - person Tensibai; 18.09.2017
comment
В любом случае, это ошибка, и о ней следует сообщить (вероятно, в список рассылки R-devel). - person Roland; 18.09.2017
comment
@ Роланд Ты сделал это? - person Konrad Rudolph; 19.09.2017
comment
@KonradRudolph Я никогда не публиковал сообщения ни в одном списке рассылки и не планирую начинать сейчас. Очень жаль, что доступ к системе отслеживания проблем R пришлось ограничить. - person Roland; 19.09.2017
comment
Да, ошибка зарегистрирована и исправлена. - person Homer White; 19.09.2017
comment
@Homer Вы могли бы ответить сами и, возможно, изменить заголовок после того, как исправление будет в стабильной версии (что я и сделал в аналогичном случае stackoverflow.com/questions/ 30035939/ ) - person Frank; 20.09.2017
comment
Спасибо за предложение @Frank, я принял его. - person Homer White; 20.09.2017