Quais são as diferenças entre “=” e “<-" em R?

Quais são as diferenças entre os operadores de atribuição = e <- em R?

Eu sei que os operadores são um pouco diferentes, como mostra este exemplo

 x <- y <- 5 x = y = 5 x = y <- 5 x <- y = 5 # Error in (x <- y) = 5 : could not find function "<-<-" 

Mas esta é a única diferença?

A diferença nos operadores de atribuição é mais clara quando você os usa para definir um valor de argumento em uma chamada de function. Por exemplo:

 median(x = 1:10) x ## Error: object 'x' not found 

Nesse caso, x é declarado dentro do escopo da function, portanto, ele não existe na área de trabalho do usuário.

 median(x < - 1:10) x ## [1] 1 2 3 4 5 6 7 8 9 10 

Nesse caso, x é declarado na área de trabalho do usuário, para que você possa usá-lo após a conclusão da chamada de function.


Há uma preferência geral entre a comunidade R por usar < - para atribuição (diferente de assinaturas de function) para compatibilidade com versões (muito) antigas do S-Plus. Note que os espaços ajudam a esclarecer situações como

 x< -3 # Does this mean assignment? x <- 3 # Or less than? x < -3 

A maioria dos IDEs R possui atalhos de teclado para facilitar a digitação. Ctrl + = no Architect, Alt + - no RStudio ( Option + - no macOS), Shift + - (sublinhado) no emacs + ESS.


Se você preferir escrever = a < - mas quer usar o símbolo de atribuição mais comum para código liberado publicamente (no CRAN, por exemplo), então você pode usar uma das funções tidy_* no pacote formatR para replace automaticamente = por < - .

 library(formatR) tidy_source(text = "x=1:5", arrow = TRUE) ## x < - 1:5 

A resposta para a pergunta "Por que x < - y = 5 lança um erro, mas não x < - y <- 5 ?" é "é baixo para a magia contida no parser". A syntax de R contém muitos casos ambíguos que precisam ser resolvidos de uma forma ou de outra. O analisador escolhe resolver os bits da expressão em ordens diferentes, dependendo se = ou < - foi usado.

Para entender o que está acontecendo, você precisa saber que a atribuição retorna silenciosamente o valor atribuído. Você pode ver isso com mais clareza ao imprimir explicitamente, por exemplo print(x < - 2 + 3) .

Em segundo lugar, fica mais claro se usarmos a notação de prefixo para atribuição. assim

 x < - 5 `<-`(x, 5) #same thing y = 5 `=`(y, 5) #also the same thing 

O analisador interpreta x < - y <- 5 como

 `< -`(x, `<-`(y, 5)) 

Podemos esperar que x < - y = 5 seria então

 `< -`(x, `=`(y, 5)) 

mas na verdade é interpretado como

 `=`(`< -`(x, y), 5) 

Isso ocorre porque = é menor precedência que < - , conforme mostrado na página de ajuda ?Syntax .

O guia de estilo R do Google simplifica o problema proibindo o “=” para atribuição. Não é uma má escolha.

https://google.github.io/styleguide/Rguide.xml

O manual R entra em detalhes agradáveis ​​em todos os 5 operadores de atribuição.

http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html

De acordo com John Chambers, o operador = só é permitido no “nível superior”, o que significa que não é permitido em estruturas de controle como if , tornando ilegal o seguinte erro de programação.

 > if(x = 0) 1 else x Error: syntax error 

Como ele escreve, “Desabilitar o novo formulário de atribuição [=] em expressões de controle evita erros de programação (como o exemplo acima) que são mais prováveis ​​com o operador de igualdade do que com outras atribuições de S.”

Você pode fazer isso se estiver “isolado da estrutura lógica circundante, por chaves ou um par extra de parênteses”, portanto, if ((x = 0)) 1 else x funcionaria.

Veja http://developer.r-project.org/equalAssign.html

x = y = 5 é equivalente a x = (y = 5) , porque os operadores de atribuição “agrupam” da direita para a esquerda, o que funciona. Significado: atribua 5 a y , deixando o número 5; e então atribua 5 a x .

Isto não é o mesmo que (x = y) = 5 , o que não funciona! Significado: atribua o valor de y para x , deixando o valor de y ; e então atribuir 5 a, umm …, o que exatamente?

Quando você mistura os diferentes tipos de operadores de atribuição, < - liga mais estreito que = . Então x = y < - 5 é interpretado como x = (y < - 5) , o que é o caso que faz sentido.

Infelizmente, x < - y = 5 é interpretado como (x < - y) = 5 , o que é o caso que não funciona!

Veja ?Syntax e ?assignOps para as ?assignOps de precedência (binding) e de agrupamento.

Os operadores < - e = atribuem ao ambiente no qual eles são avaliados. O operador < - pode ser usado em qualquer lugar, enquanto o operador = é permitido somente no nível superior (por exemplo, na expressão completa digitada no prompt de comando) ou como uma das subexpressões em uma lista de expressões.

Quais são as diferenças entre os operadores de atribuição = e < - em R?

Como seu exemplo mostra, = e < - tem precedência de operador ligeiramente diferente (que determina a ordem de avaliação quando eles são misturados na mesma expressão). De fato, a ?Syntax em R fornece a seguinte tabela de precedência do operador, do maior para o menor:

 … '-> ->>' rightwards assignment '< - <<-' assignment (right to left) '=' assignment (right to left) … 

Mas esta é 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 de outra forma. Até mesmo a documentação de ?assignOps afirma que existem mais diferenças:

O operador < - pode ser usado em qualquer lugar, enquanto o operador = é permitido somente no nível superior (por exemplo, na expressão completa digitada no prompt de comando) ou como uma das subexpressões em uma lista de expressões.

Não vamos colocar um ponto muito bom nisso: a documentação R está (sutilmente) errada [ 1 ] . Isso é fácil de mostrar: só precisamos encontrar um contra-exemplo do operador = que não seja (a) no nível superior, nem (b) uma subexpressão em uma lista de expressões preparadas (ou seja, {…; …} ). - Sem mais delongas:

 x # Error: object 'x' not found sum((x = 1), 2) # [1] 3 x # [1] 1 

Claramente, realizamos uma tarefa usando = fora dos contextos (a) e (b). Então, por que a documentação de um recurso principal da linguagem R está errada há décadas?

É porque na syntax de R o símbolo = tem dois significados distintos que são rotineiramente confundidos:

  1. O primeiro significado é como um operador de atribuição . Isso é tudo o que conversamos até agora.
  2. O segundo significado não é um operador, mas sim um token de syntax que sinaliza o argumento nomeado passando em uma chamada de function. Ao contrário do operador = , ele não executa nenhuma ação em tempo de execução, ele 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 token que define a passagem do argumento nomeado: 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 um deles irá gerar um erro “inesperado” = 'in' bla ›”.

Em qualquer outro contexto, = refere-se à chamada do operador de atribuição. Em particular, simplesmente colocar parênteses em torno da subexpressão torna qualquer um dos itens acima (a) válido 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 tal código é atroz (e você pode estar certo). Mas eu peguei esse código da function base::file.copy (substituindo < - com = ) - é um padrão difundido em grande parte da base de código principal do R.

A explicação original de John Chambers , sobre a qual a documentação R provavelmente se baseia, explica isso corretamente:

[ = atribuição é] permitida em apenas dois lugares na 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: menti mais cedo. Existe uma diferença adicional entre os operadores = e < - : eles chamam funções distintas. Por padrão, essas funções fazem a mesma coisa, mas você pode replace qualquer uma delas separadamente para alterar o comportamento. Por outro lado, < - e -> (atribuição da esquerda para a direita), embora sintaticamente distintas, sempre chamam a mesma function. Substituir um também substitui o outro. Sabendo que isso raramente é prático, mas pode ser usado para algumas brincadeiras divertidas .

Isso também pode aumentar a compreensão da diferença entre esses dois operadores:

 df < - data.frame( a = rnorm(10), b <- rnorm(10) ) 

Para o primeiro elemento, R atribuiu valores e nome próprio, enquanto o nome do segundo elemento parece um pouco estranho.

 str(df) # 'data.frame': 10 obs. of 2 variables: # $ a : num 0.6393 1.125 -1.2514 0.0729 -1.3292 ... # $ b....rnorm.10.: num 0.2485 0.0391 -1.6532 -0.3366 1.1951 ... 

R versão 3.3.2 (2016-10-31); macOS Sierra 10.12.1