Если/else строит внутренние и внешние функции
Когда я смотрю на функции R, я часто нахожу следующую структуру:
f <- function(exp=T) {
if (exp)
a <- 1
else
a <- 2
}
f()
f(F)
Это будет работать без ошибок. Но выполнение внутреннего кода функции вызывает ошибку, так как R, вероятно, предполагает, что оператор завершается после первого присваивания a <- 1
и не может обрабатывать следующее.
exp=T
if (exp)
a <- 1
else
a <- 2
Теперь это имеет смысл для меня, но мне все же хотелось бы понять, почему поведение исполняемого кода отличается при выполнении внутри или вне функции.
Ответы
Ответ 1
Это следствие использования интерактивной оболочки (REPL) для запуска скриптов:
После первой ветки оболочка увидела полный оператор, поэтому предполагает, что вы сделали ввод. К сожалению, R использует одну и ту же оболочку для интерпретации скриптов, даже если они не введены в интерактивном режиме, поэтому даже когда вы сохраняете оператор if
в файл и source
его (или передаете его в R), вы получите ошибку на ветвь else
.
Но следующее будет прекрасно работать:
if (exp) a <- 1 else a <- 2
Здесь интерпретатор проглатывает строку и выполняет ее.
В вашей функции можно предположить, что то же самое относится - и это так! Однако сама функция начинается с открытой скобки в вашем случае, поэтому R должен читать до тех пор, пока не найдет подходящую закрывающую фигуру. В отличие от этого, объявите эту функцию:
f <- function (exp)
if (exp)
a <- 1
else
a <- 2
В R вы можете определять функции без фигурных скобок вокруг тела. Но приведенный выше код не будет работать по той же причине, что и автономный if
без брекетов. В отличие от этого, если бы я написал if
в одной строке, этот код снова будет работать.
Кстати, ваша функция использует назначение переменной, которая не используется. Вы можете (должны) сделать следующее:
f <- function (exp) {
if (exp)
1
else
2
}
... и то же самое при использовании if
внутри оболочки:
a <- if (exp) 1 else 2
потому что в R, if
- это выражение, которое возвращает значение.
Ответ 2
Резюме:
Есть только два способа, чтобы R знал, что предложение else принадлежит к предложению if выше:
- Весь оператор if... else (и, возможно, другие операторы) заключен в фигурные скобки;
- Слово else появляется в той же строке, что и конец предложения if.
Доказательства:
Вышеприведенное обсуждение помогло мне, но я надеюсь, что могу предложить полезный каламбур. Да, правильно, что
f <- function (exp)
if (exp)
1
else
2
терпит неудачу с классическим сообщением Error: unexpected 'else' in "else"
из-за неуспеха R, чтобы продолжить чтение. 1. Два способа были правильно предложены для того, чтобы R продолжал читать мимо 1:
f <- function (exp) {
if (exp)
1
else
2
}
и
f <- function (exp) if (exp) 1 else 2
Но есть еще третий способ, который еще не упоминается --- просто переместите else
вверх по строке. Таким образом, следующее также работает, потому что R знает, что нужно читать за 1:
f <- function (exp)
if (exp)
1 else
2
Я думаю, что ключевой момент состоит в том, чтобы либо скопировать весь элемент функции, либо убедиться, что else
встречается в той же строке, что и конец предложения if, так что R знает, что нужно читать. Вот почему работает однострочное решение. Именно поэтому это работает:
f <- function (exp)
if (exp) {
1
} else
2
Но это не удается:
f <- function (exp)
if (exp) {
1
}
else
2
И используя более стандартную привязку тела функции, это тоже работает:
f <- function (exp) {
if (exp) {
1
}
else
2
}
Но независимо от того, строим ли мы функцию, это красная селедка. Важно только скобки и расположение else
. Таким образом, эти работы:
{
if (exp) {
1
}
else
2
}
if (exp) {
1
} else
2
но это не удается:
if (exp) {
1
}
else
2
и чтобы продемонстрировать мое утверждение 1 вверху, это работает:
{
x <- 4
if (exp)
1
else
2
}