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, pois este exemplo mostra
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
Mas essa é a única diferença?
r
assignment-operator
r-faq
csgillespie
fonte
fonte
<-
símbolo vêm de teclados antigos da APL, que na verdade tinham uma única<-
tecla.Respostas:
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,?Syntax
em R fornece a seguinte tabela de precedência do operador, da mais alta para a mais baixa: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
?assignOps
afirma que existem mais diferenças: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: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:=
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…
... 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: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:Mas também:
Agora você pode objetar que esse código é atroz (e você pode estar certo). Mas peguei esse código da
base::file.copy
funçã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:
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 .fonte
?
realmente está no meio=
e<-
, o que tem consequências importantes ao substituir?
, e praticamente nenhuma outra.main/gram.y
), a precedência de?
está documentada corretamente e é menor que ambos=
e<-
.=
receba um tratamento especial antes que a árvore de análise seja construída. Talvez relacionado a argumentos de função, faz sentido quefoo(x = a ? b)
procuraríamos=
antes de analisar o restante da expressão.A diferença nos operadores de atribuição é mais clara quando você os utiliza para definir um valor de argumento em uma chamada de função. Por exemplo:
Nesse caso,
x
é declarado no escopo da função, portanto, não existe no espaço de trabalho do usuário.Nesse caso,
x
é declarado no espaço de trabalho do usuário, para que você possa usá-lo após a conclusão da chamada da função.Existe uma preferência geral entre a comunidade R pelo uso
<-
para atribuição (exceto nas assinaturas de funções) para compatibilidade com (muito) versões antigas do S-Plus. Observe que os espaços ajudam a esclarecer situações comoA 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 preferir escrever
=
a<-
mas quiser usar o símbolo de atribuição mais comum para o código lançado publicamente (em CRAN, por exemplo), então você pode usar uma dastidy_*
funções noformatR
pacote para substituir automaticamente=
com<-
.A resposta para a pergunta "Por que
x <- y = 5
lançar um erro, mas nãox <- y <- 5
?" é "Tudo depende da magia contida no analisador". A sintaxe de R contém muitos casos ambíguos que precisam ser resolvidos de uma maneira ou de outra. O analisador escolhe resolver os bits da expressão em diferentes ordens, dependendo de se foi=
ou<-
não usado.Para entender o que está acontecendo, você precisa saber que a atribuição silenciosamente retorna o valor que foi designado. Você pode ver isso mais claramente imprimindo explicitamente, por exemplo
print(x <- 2 + 3)
.Em segundo lugar, fica mais claro se usarmos notação de prefixo para atribuição. assim
O analisador interpreta
x <- y <- 5
comoPodemos esperar que
x <- y = 5
seria entãomas na verdade é interpretado como
Isso ocorre porque a
=
precedência é menor do que<-
, conforme mostrado na?Syntax
página de ajuda.fonte
median((x = 1:10))
tem o mesmo efeito quemedian(x <- 1:10)
.x <- x = 5
é interpretada está um pouco errada: Na realidade, R a interpreta como`<-<-`(x, y = 5, value = 5)
(o que em si é mais ou menos equivalente atmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)
). Caramba!=
em uma chamada de função não realiza atribuição e não é um operador de atribuição. É uma expressão R analisada totalmente distinta, que por acaso usa o mesmo caractere. Além disso, o código que você mostra não “declara”x
no escopo da função. A declaração da função executa a referida declaração. A chamada de função não (fica um pouco mais complicada com...
argumentos nomeados ).O guia de estilo R do Google simplifica o problema ao proibir o "=" para atribuição. Não é uma má escolha.
https://google.github.io/styleguide/Rguide.xml
O manual R entra em detalhes interessantes em todos os 5 operadores de atribuição.
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
fonte
x<-y
quandox < -y
foi feita me irrita tanto que eu pessoalmente prefiro=
. Ter seu código depende da presença de espaço em branco não me parece bom. Não há problema em sugerir espaçamento como orientação de estilo, mas para que seu código seja executado de maneira diferente, independentemente de haver um espaço ou não? E se você reformatar seu código ou usar a pesquisa e a substituição, o espaço em branco às vezes pode desaparecer e o código dá errado. Isso não é um problema=
. IIUC, proibir=
equivale a exigir "<-
"; ou seja, 3 caracteres, incluindo um espaço, não apenas "<-
".TRUE
por R. Portanto, se você pretende testar sex
é menor que-y
, pode escrever oif (x<-y)
que não avisa ou erro e parece funcionar bem. Só seráFALSE
quandoy=0
.=
e usa<-
, é difícil argumentar que uma etapa extragrep "[^<]<-[^ ]" *.R
não é necessária.=
não precisa de talgrep
.<-
se você pode usar=
? Em 99,99% das vezes=
é bom. Às vezes você precisa<<-
, porém, que é uma história diferente.x = y = 5
é equivalente ax = (y = 5)
, porque os operadores de atribuição "agrupam" da direita para a esquerda, o que funciona. Significado: atribua 5 ay
, deixando o número 5; e depois atribua esse 5 ax
.Não é o mesmo que
(x = y) = 5
, o que não funciona! Significado: atribua o valor dey
ax
, deixando o valor dey
; e depois atribui 5 a, umm ..., o que exatamente?Quando você mistura os diferentes tipos de operadores de atribuição, as
<-
ligações são mais apertadas que=
. Então,x = y <- 5
é interpretado comox = (y <- 5)
, que é o caso que faz sentido.Infelizmente,
x <- y = 5
é interpretado como(x <- y) = 5
, que é o caso que não funciona!Consulte
?Syntax
e?assignOps
para as regras de precedência (encadernação) e agrupamento.fonte
<- <<-
está acima=
na tabela de precedência, o que significa que<-
será realizado primeiro. Então,x <- y = 5
deve ser executado como(x <- y) = 5
.De acordo com John Chambers, o operador
=
é permitido apenas no "nível superior", o que significa que não é permitido em estruturas de controle comoif
, tornando ilegal o seguinte erro de programação.Como ele escreve, "A exclusão do novo formulário de atribuição [=] nas expressões de controle evita erros de programação (como o exemplo acima) que são mais prováveis com o operador igual do que com outras atribuições S."
Você pode fazer isso se estiver "isolado da estrutura lógica circundante, por chaves ou um par extra de parênteses", assim
if ((x = 0)) 1 else x
funcionaria.Consulte http://developer.r-project.org/equalAssign.html
fonte
x==0
quase sempre significa isso.x=0
atribuiçãox<-0
!=
o mínimo possível porque=
e==
pareço tão semelhante.if(x = 0) 1 else x
gera um erro, ajudando-me a encontrar e corrigir um erro.if(x <- 1) 1 else x
não gera um erro e é muito confuso.else
valor, você quis escrever dessa maneira?", Mas isso pode ser um sonho ...Os operadores
<-
e=
atribuem ao ambiente em que são avaliados. 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.fonte
x <- 42
por si só, é uma afirmação; noif (x <- 42) {}
que seria uma expressão, e não é válido. Para ser claro, isso não tem nada a ver com você estar no ambiente global ou não.1 + (x = 2)
function() x = 1
,repeat x = 1
,if (TRUE) x = 1
....Isso também pode aumentar a compreensão da diferença entre esses dois operadores:
Para o primeiro elemento, R atribuiu valores e nome próprio, enquanto o nome do segundo elemento parece um pouco estranho.
R versão 3.3.2 (31-10-2016); macOS Sierra 10.12.1
fonte
data.frame
tenta utilizar o nome da variável fornecida como o nome do elemento na trama de dados)make.names("b <- rnorm(10)")
.