¿Cuáles son las diferencias entre los operadores de asignación =
y <-
en R?
Sé que los operadores son ligeramente diferentes, como muestra este ejemplo
x <- y <- 5
x = y = 5
x = y <- 5
x <- y = 5
# Error in (x <- y) = 5 : could not find function "<-<-"
¿Pero es esta la única diferencia?
r
assignment-operator
r-faq
csgillespie
fuente
fuente
<-
símbolo provienen de viejos teclados APL que en realidad tenían una sola<-
tecla.Respuestas:
Como muestra su ejemplo,
=
y<-
tienen una precedencia de operador ligeramente diferente (que determina el orden de evaluación cuando se mezclan en la misma expresión). De hecho,?Syntax
en R da la siguiente tabla de precedencia de operadores, de mayor a menor:¿Pero es esta la única diferencia?
Como estaba preguntando acerca de los operadores de asignación : sí, esa es la única diferencia. Sin embargo, sería perdonado por creer lo contrario. Incluso la documentación R de
?assignOps
afirma que hay más diferencias:No pongámosle un punto demasiado fino: la documentación de R es (sutilmente) incorrecta [ 1 ] . Esto es fácil de mostrar: solo necesitamos encontrar un contraejemplo del
=
operador que no esté (a) en el nivel superior, ni (b) una subexpresión en una lista de expresiones entre paréntesis (es decir{…; …}
). - Sin más preámbulos:Claramente hemos realizado una tarea, utilizando
=
, fuera de los contextos (a) y (b). Entonces, ¿por qué la documentación de una característica principal del lenguaje R ha estado mal durante décadas?Es porque en la sintaxis de R el símbolo
=
tiene dos significados distintos que se combinan habitualmente:=
operador, no realiza ninguna acción en tiempo de ejecución, simplemente cambia la forma en que se analiza una expresión.Veamos.
En cualquier código de la forma general ...
... el
=
es el símbolo que define el llamado argumento que pasa: es no el operador de asignación. Además,=
está completamente prohibido en algunos contextos sintácticos:Cualquiera de estos generará un error “inesperado '=' en ‹bla›”.
En cualquier otro contexto, se
=
refiere a la llamada del operador de asignación. En particular, simplemente poner paréntesis alrededor de la subexpresión hace que cualquiera de los anteriores (a) sea válido y (b) una asignación . Por ejemplo, lo siguiente realiza la asignación:Pero también:
Ahora puede objetar que dicho código es atroz (y puede que tenga razón). Pero tomé este código de la
base::file.copy
función (reemplazando<-
con=
): es un patrón generalizado en gran parte de la base de código R principal.La explicación original de John Chambers , en la que probablemente se basa la documentación de R, en realidad explica esto correctamente:
Una confesión: mentí antes. No es una diferencia adicional entre el
=
y<-
los operadores: se llama a funciones distintas. Por defecto, estas funciones hacen lo mismo, pero puede anular cualquiera de ellas por separado para cambiar el comportamiento. Por el contrario,<-
y->
(asignación de izquierda a derecha), aunque sintácticamente distintas, siempre llaman a la misma función. Anular uno también anula al otro. Saber esto rara vez es práctico, pero puede usarse para algunas travesuras divertidas .fuente
?
está realmente en el medio=
y<-
, lo que tiene consecuencias importantes al anular?
, y prácticamente nada de lo contrario.main/gram.y
), la precedencia de?
está correctamente documentada y es menor que ambas=
y<-
.=
recibirá un tratamiento especial antes de construir el árbol de análisis. Quizás relacionado con argumentos de función, tiene sentido quefoo(x = a ? b)
lo busquemos=
antes de analizar el resto de la expresión.La diferencia en los operadores de asignación es más clara cuando los usa para establecer un valor de argumento en una llamada de función. Por ejemplo:
En este caso,
x
se declara dentro del alcance de la función, por lo que no existe en el espacio de trabajo del usuario.En este caso,
x
se declara en el espacio de trabajo del usuario, por lo que puede usarlo después de que se haya completado la llamada a la función.Existe una preferencia general entre la comunidad R por usar
<-
para la asignación (que no sea en firmas de funciones) para la compatibilidad con versiones (muy) antiguas de S-Plus. Tenga en cuenta que los espacios ayudan a aclarar situaciones comoLa mayoría de los IDE de R tienen métodos abreviados de teclado para
<-
facilitar la escritura. Ctrl+ =en Architect, Alt+ -en RStudio ( Option+ -bajo macOS), Shift+ -(subrayado) en emacs + ESS.Si prefiere escribir
=
a<-
pero desea utilizar el símbolo de asignación más común para el código publicado públicamente (en CRAN, por ejemplo), entonces se puede utilizar una de lastidy_*
funciones en elformatR
paquete para reemplazar automáticamente=
con<-
.La respuesta a la pregunta "¿Por qué
x <- y = 5
arroja un error pero nox <- y <- 5
?" es "Todo depende de la magia contenida en el analizador". La sintaxis de R contiene muchos casos ambiguos que deben resolverse de una forma u otra. El analizador elige resolver los bits de la expresión en diferentes órdenes dependiendo de si se utilizó=
o no<-
.Para comprender lo que está sucediendo, debe saber que la asignación devuelve silenciosamente el valor asignado. Puede verlo más claramente imprimiendo explícitamente, por ejemplo
print(x <- 2 + 3)
.En segundo lugar, es más claro si usamos la notación de prefijo para la asignación. Entonces
El analizador interpreta
x <- y <- 5
comoPodríamos esperar que
x <- y = 5
entonces seríapero en realidad se interpreta como
Esto se debe a que
=
tiene una precedencia menor que<-
, como se muestra en la?Syntax
página de ayuda.fuente
median((x = 1:10))
tiene el mismo efecto quemedian(x <- 1:10)
.x <- x = 5
se interpreta es un poco errónea: en realidad, R la interpreta como`<-<-`(x, y = 5, value = 5)
(que en sí misma es más o menos equivalente atmp <- x; x <- `<-<-`(tmp, y = 5, value = 5)
). ¡Ay!=
en una llamada de función no realiza la asignación , y no es un operador de asignación. Es una expresión R analizada completamente distinta, que simplemente usa el mismo carácter. Además, el código que muestra no "declara"x
en el ámbito de la función. La declaración de función realiza dicha declaración. La llamada a la función no (se vuelve un poco más complicada con...
argumentos con nombre ).La guía de estilo R de Google simplifica el problema al prohibir el "=" para la asignación. No es una mala elección.
https://google.github.io/styleguide/Rguide.xml
El manual de R entra en detalles agradables en los 5 operadores de asignación.
http://stat.ethz.ch/R-manual/R-patched/library/base/html/assignOps.html
fuente
x<-y
cuandox < -y
se quiso decir, me molesta tanto que personalmente prefiero=
. Hacer que su código dependa del espacio en blanco presente no me parece bueno. ¿Está bien sugerir espacios como consejos de estilo pero para que su código se ejecute de manera diferente si hay un espacio o no? ¿Qué sucede si reformatea su código, o usa buscar y reemplazar, el espacio en blanco a veces puede desaparecer y el código sale mal? Eso no es un problema con=
. IIUC, prohibir=
equivale a exigir "<-
"; es decir, 3 caracteres incluyendo un espacio, no solo "<-
".TRUE
R. no considera ningún valor distinto de 0. Por lo tanto, si tiene la intención de probar six
es menor que-y
, puede escribirif (x<-y)
lo que no advertirá ni producirá errores, y parecerá que funciona bien. Sin embargo, solo seráFALSE
cuandoy=0
.=
y usa<-
, es difícil argumentar quegrep "[^<]<-[^ ]" *.R
no se necesita un paso adicional .=
no necesita talgrep
.<-
si puedes usar=
? En el 99,99% de las veces=
está bien. Sin<<-
embargo, a veces es necesario , que es una historia diferente.x = y = 5
es equivalente ax = (y = 5)
, porque los operadores de asignación "agrupan" de derecha a izquierda, lo que funciona. Significado: asignar 5 ay
, dejando el número 5; y luego asigna ese 5 ax
.¡Esto no es lo mismo
(x = y) = 5
que no funciona! Significado: asignar el valor dey
ax
, dejando el valor dey
; y luego asigna 5 a, umm ..., ¿qué exactamente?Cuando combina los diferentes tipos de operadores de asignación, los
<-
enlaces se ajustan más que=
. Entoncesx = y <- 5
se interpreta comox = (y <- 5)
, que es el caso que tiene sentido.Lamentablemente,
x <- y = 5
se interpreta como(x <- y) = 5
, que es el caso que no funciona!Vea
?Syntax
y?assignOps
para la precedencia (enlace) y las reglas de agrupación.fuente
<- <<-
está arriba de la=
tabla de precedencia, lo que significa<-
que se ejecutará primero. Por lo tanto,x <- y = 5
debe ejecutarse como(x <- y) = 5
.Según John Chambers, el operador
=
solo está permitido en "el nivel superior", lo que significa que no está permitido en estructuras de control comoif
, lo que hace que el siguiente error de programación sea ilegal.Como escribe, "No permitir la nueva forma de asignación [=] en las expresiones de control evita errores de programación (como el ejemplo anterior) que son más probables con el operador igual que con otras asignaciones de S".
Puede lograr hacer esto si está "aislado de la estructura lógica circundante, mediante llaves o un par de paréntesis extra", así
if ((x = 0)) 1 else x
funcionaría.Ver http://developer.r-project.org/equalAssign.html
fuente
x==0
casi siempre se entiende en su lugar.x=0
que la tarea terminex<-0
!=
menor cantidad posible porque=
y me==
veo muy similar.if(x = 0) 1 else x
arroja un error, ayudándome a encontrar y corregir un error.if(x <- 1) 1 else x
no arroja un error y es muy confuso.else
valor, ¿se refiere a escribir de esa manera?", Pero, que puede ser una quimera ...Los operadores
<-
y=
asignan en el entorno en el que se evalúan. El operador<-
se puede usar en cualquier lugar, mientras que el operador=
solo se permite en el nivel superior (por ejemplo, en la expresión completa escrita en el símbolo del sistema) o como una de las subexpresiones en una lista de expresiones entre paréntesis.fuente
x <- 42
por sí solo, es una declaración; enif (x <- 42) {}
sería una expresión, y no es válida. Para ser claros, esto no tiene nada que ver con si estás en el entorno global o no.1 + (x = 2)
function() x = 1
,repeat x = 1
,if (TRUE) x = 1
....Esto también puede ayudar a comprender la diferencia entre esos dos operadores:
Para el primer elemento, R ha asignado valores y nombre propio, mientras que el nombre del segundo elemento parece un poco extraño.
R versión 3.3.2 (31/10/2016); macOS Sierra 10.12.1
fuente
data.frame
intenta usar el nombre de la variable proporcionada como el nombre del elemento en el marco de datos)make.names("b <- rnorm(10)")
.