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

Вызов функции 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.

4b9b3361

Ответ 1

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

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

Ответ 2

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

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"

Ответ 3

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, из теста Франка в чате, код follwing имеет ту же проблему:

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 не позволяет пробелы между # и define.

После копания для этого я ошибаюсь, из gcc doc:

Пробел также разрешен до и после "#".

Итак, возможно, что-то вокруг этой части кода, но над моей головой точно определить, что именно.