Когда мне нужны круглые скобки вокруг оператора if для управления последовательностью формулы в R?
Я пытаюсь разделить число на сумму результата двух операторов if. По какой-то причине R игнорирует круглые скобки вокруг обоих операторов if после завершения первого оператора if и выполняет деление только на первый оператор if. При добавлении скобок вокруг первого оператора if формула работает так, как ожидалось.
Вопрос: почему это так?
Замена операторов if на ifelse (y == 2,4,1) решает его, а также дополнительные скобки. Мне любопытно, почему первый тест дает мне неожиданный результат.
x <- 1
y <- 2
z <- 4
test1 <- z/(if(y==2){4}else{1}+if(x==1){4}else{1})
> print(test1)
[1] 1
test2 <- z/((if(y==2){4}else{1})+if(x==1){4}else{1})
> print(test2)
[1] 0.5
Я ожидаю, что результат test1 и test2 будет равен 0.5
Ответы
Ответ 1
Отличный вопрос. Из определения языка R:
Вычисление в R состоит из последовательно оценивающих операторов. Утверждения, такие как x & lt; -1:10 или mean (y), могут быть разделены точкой с запятой или новой строкой.
Далее под if
:
Оператор if/else условно оценивает два оператора. Существует условие, которое оценивается, и если значение равно TRUE, то выполняется первый оператор; в противном случае второе утверждение будет оценено. Оператор if/else возвращает в качестве значения значение оператора, который был выбран. Формальный синтаксис:
if ( statement1 )
statement2
else
statement3
Проблема, с которой вы столкнулись, заключается в том, что {1}+if(x==1){4}else{1}
является допустимым оператором, поэтому R интерпретирует его как оператор3. Другими словами, начиная с else
, все (внутри блока) вплоть до новой строки или точки с запятой встречается только тогда, когда оператор if
имеет значение FALSE.
Обычно в чем-то вроде
if (y == 2) {
4
} else {
1
}
мы понимаем, что после последней фигурной скобки оператор if завершился, но это конец строки, а не заключительная фигурная скобка, означающая конец выражения. Например, это не создает a
if (y == 2) {
4
} else {
1
} -> a
Ответ 2
Второй оператор возвращает z/(4 + 4), эрго 0,5, а для первого оператора он оценивает только первое предложение if(). Доказательство:
> z/(if(y==2){4}else{1}+if(x==1){4}else{3})
[1] 1
Ответ 3
Еще один способ взглянуть на это: для меня это сводится к тому, что:
{
используется для группировки операторов, а не их разграничения.
- Это не является частью синтаксиса конструкций потока управления или определения функции, как в скобках, несмотря на то, что стандартное использование часто выглядит так, как есть.
- По своей природе символы потока управления разграничивают операторы и, таким образом, имеют более низкий приоритет, чем любой оператор, см.:
lobstr::ast(if (TRUE) 1 else 0 + 4)
#> o-'if'
#> +-TRUE
#> +-1
#> \-o-'+'
#> +-0
#> \-4
lobstr::ast(if (TRUE) 1 else {0} + 4)
#> o-'if'
#> +-TRUE
#> +-1
#> \-o-'+'
#> +-o-'{'
#> | \-0
#> \-4
lobstr::ast(if (TRUE) 1 else {0} <- 4) # '<-' has very low precedence amongst operators
#> o-'if'
#> +-TRUE
#> +-1
#> \-o-'<-'
#> +-o-'{'
#> | \-0
#> \-4
lobstr::ast(if (TRUE) 1 else {0} ? 4) # '?' has the lowest precedence amongst operators
#> o-'if'
#> +-TRUE
#> +-1
#> \-o-'?'
#> +-o-'{'
#> | \-0
#> \-4
Created on 2019-08-19 by the reprex package (v0.3.0)
В этом свете результат неудивителен.
Чтобы проиллюстрировать это далее, используйте случай OP:
lobstr::ast(z/(if(y==2){4}else{1}+if(x==1){4}else{1}))
#> o-'/'
#> +-z
#> \-o-'('
#> \-o-'if'
#> +-o-'=='
#> | +-y
#> | \-2
#> +-o-'{'
#> | \-4
#> \-o-'+'
#> +-o-'{'
#> | \-1
#> \-o-'if'
#> +-o-'=='
#> | +-x
#> | \-1
#> +-o-'{'
#> | \-4
#> \-o-'{'
#> \-1
Created on 2019-08-19 by the reprex package (v0.3.0)
Ответ 4
Этот вопрос вызвал обсуждение в списке рассылки R-devel,
https://r.789695.n4.nabble.com/Documenting-else-s-greed-td4758844.html.
Способ R обрабатывает это удивительно, потому что в if/else и некоторых других конструкциях открывающие фигурные скобки, если таковые имеются, являются частью вычисляемого выражения, а не разделителями синтаксиса. В частности, выражение не обязательно заканчивается закрывающей скобкой. Например, {2} + 3
и 2 + 3
являются эквивалентными выражениями, поэтому первая команда ниже дает 0, а не 3 (результат второй также равен 0, как и ожидалось).
if(TRUE) 0 else {2} + 3
## [1] 0
if(TRUE) 0 else 2 + 3
## [1] 0
Эта путаница возникает главным образом в конструкциях 'else' из 'if', но не ограничивается ими. Например, это определяет функцию с телом x^2 + 1
по тем же причинам ({x^2} + 1
эквивалентно x^2 + 1
), хотя можно ожидать ошибки в первой строке ниже:
f <- function(x){x^2} + 1
f(2)
## [1] 5