Каковы различия между операторами присваивания =и <-в R?
Как ваш пример показывает, =и <-имеют несколько иной приоритет оператора (который определяет порядок вычисления , когда они смешиваются в одном выражении). На самом деле, ?Syntaxв R выдает следующую таблицу приоритетов операторов, от высшего к низшему:
…
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)
…
Но единственная ли это разница?
Поскольку вы спрашивали об операторах присваивания : да, это единственная разница. Тем не менее, вы были бы прощены за то, что поверили в обратное. Даже документация R ?assignOpsутверждает, что есть больше различий:
Оператор <-может использоваться где угодно, тогда как оператор =допускается только на верхнем уровне (например, в полном выражении, набранном в командной строке) или в качестве одного из подвыражений в ограниченном списке выражений.
Давайте не будем заострять внимание на этом: документация на R (слегка) неверна [ 1 ] . Это легко показать: нам просто нужно найти контрпример для =оператора, который не (а) не находится на верхнем уровне и не (b) является подвыражением в ограниченном списке выражений (то есть {…; …}). - Без дальнейших церемоний:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Ясно, что мы выполнили присваивание =вне контекста (a) и (b). Итак, почему документация о ядре языка R была неправильной в течение десятилетий?
Это потому, что в синтаксисе R символ =имеет два разных значения, которые обычно смешиваются:
- Первое значение как оператор присваивания . Это все, о чем мы говорили до сих пор.
- Второе значение - не оператор, а синтаксический маркер, который сигнализирует именованный аргумент, передаваемый в вызове функции. В отличие от
=оператора, он не выполняет никаких действий во время выполнения, он просто изменяет способ анализа выражения.
Посмотрим.
В любой части кода общего вида ...
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... =это токен, который определяет передачу именованного аргумента: это не оператор присваивания. Кроме того, =полностью запрещено в некоторых синтаксических контекстах:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Любое из них вызовет ошибку «неожиданно» = «в‹ bla ›».
В любом другом контексте =относится к вызову оператора присваивания. В частности, простое размещение скобок вокруг подвыражения делает любое из вышеперечисленного (а) действительным и (б) назначением . Например, следующее выполняет назначение:
median((x = 1 : 10))
Но и:
if (! (nf = length(from))) return()
Теперь вы можете возразить, что такой код ужасен (и вы можете быть правы). Но я взял этот код из base::file.copyфункции (заменив <-на =) - это распространенный шаблон в большей части основной кодовой базы R.
Оригинальное объяснение Джона Chambers , которым документация по R, вероятно , на основе, на самом деле объясняет это правильно:
[ =присваивание] разрешено только в двух местах грамматики: на верхнем уровне (как полная программа или пользовательское выражение); и когда он изолирован от окружающей логической структуры, скобками или дополнительной парой скобок.
Признание: я солгал раньше. Там является одна дополнительная разница между =и <-операторами: они называют различные функции. По умолчанию эти функции делают то же самое, но вы можете переопределить любую из них отдельно, чтобы изменить поведение. В отличие от этого, <-и ->(назначение слева направо), хотя синтаксически различны, всегда вызывают одну и ту же функцию. Переопределение одного переопределяет другое. Знание этого редко бывает практичным, но его можно использовать для забавных махинаций .
<-символа приходят от старых APL клавиатур , которые фактически имели один<-ключ на них.