Quais são as diferenças entre os operadores de atribuição =e <-em R?
Como mostra seu exemplo, =e <-tem precedência de operador ligeiramente diferente (que determina a ordem da avaliação quando eles são misturados na mesma expressão). De fato, ?Syntaxem R fornece a seguinte tabela de precedência do operador, da mais alta para a mais baixa:
…
‘-> ->>’ rightwards assignment
‘<- <<-’ assignment (right to left)
‘=’ assignment (right to left)
…
Mas essa é a única diferença?
Desde que você estava perguntando sobre os operadores de atribuição : sim, essa é a única diferença. No entanto, você seria perdoado por acreditar no contrário. Até a documentação R ?assignOpsafirma que existem mais diferenças:
O operador <-pode ser usado em qualquer lugar, enquanto o operador =é permitido apenas no nível superior (por exemplo, na expressão completa digitada no prompt de comando) ou como uma das subexpressões em uma lista entre expressões.
Não vamos enfatizar muito bem: a documentação do R está (sutilmente) errada [ 1 ] . Isso é fácil de mostrar: precisamos apenas encontrar um contra-exemplo do =operador que não esteja (a) no nível superior nem (b) uma subexpressão em uma lista de expressões (ie {…; …}). - Sem mais delongas:
x
# Error: object 'x' not found
sum((x = 1), 2)
# [1] 3
x
# [1] 1
Claramente, realizamos uma atribuição, usando =, fora dos contextos (a) e (b). Então, por que a documentação de um recurso central da linguagem R está errada há décadas?
É porque na sintaxe de R o símbolo =tem dois significados distintos que são rotineiramente confundidos:
- O primeiro significado é como um operador de atribuição . É disso que falamos até agora.
- O segundo significado não é um operador, mas um token de sintaxe que sinaliza o argumento chamado passando em uma chamada de função. Ao contrário do
=operador, ele não executa nenhuma ação no tempo de execução, apenas altera a maneira como uma expressão é analisada.
Vamos ver.
Em qualquer parte do código da forma geral…
‹function_name›(‹argname› = ‹value›, …)
‹function_name›(‹args›, ‹argname› = ‹value›, …)
... o =é o sinal que define chamado argumento passando: ele é não o operador de atribuição. Além disso, =é totalmente proibido em alguns contextos sintáticos:
if (‹var› = ‹value›) …
while (‹var› = ‹value›) …
for (‹var› = ‹value› in ‹value2›) …
for (‹var1› in ‹var2› = ‹value›) …
Qualquer uma dessas opções gerará um erro “inesperado '=' em ‹bla›”.
Em qualquer outro contexto, =refere-se à chamada do operador de atribuição. Em particular, apenas colocar parênteses em torno da subexpressão torna qualquer uma das alternativas (a) acima e (b) uma atribuição . Por exemplo, o seguinte executa a atribuição:
median((x = 1 : 10))
Mas também:
if (! (nf = length(from))) return()
Agora você pode objetar que esse código é atroz (e você pode estar certo). Mas peguei esse código da base::file.copyfunção (substituindo <-por =) - é um padrão generalizado em grande parte da base de código R principal.
A explicação original de John Chambers , na qual a documentação do R provavelmente está baseada, na verdade explica isso corretamente:
[a =atribuição é] permitida em apenas dois lugares da gramática: no nível superior (como um programa completo ou expressão digitada pelo usuário); e quando isolado da estrutura lógica circundante, por chaves ou um par extra de parênteses.
Uma confissão: eu menti antes. Não é uma diferença adicional entre a =e <-operadores: eles chamam funções distintas. Por padrão, essas funções fazem a mesma coisa, mas você pode substituí-las separadamente para alterar o comportamento. Por outro lado, <-e ->(atribuição da esquerda para a direita), embora sintaticamente distintos, sempre chamam a mesma função. Substituir um também substitui o outro. Saber isso raramente é prático, mas pode ser usado para algumas travessuras divertidas .
<-símbolo vêm de teclados antigos da APL, que na verdade tinham uma única<-tecla.