Los símbolos en Julia son los mismos que en Lisp, Scheme o Ruby. Sin embargo, las respuestas a esas preguntas relacionadas no son realmente satisfactorias , en mi opinión. Si lee esas respuestas, parece que la razón por la cual un símbolo es diferente de una cadena es que las cadenas son mutables mientras que los símbolos son inmutables, y los símbolos también están "internados", sea lo que sea que eso signifique. Las cuerdas son mutables en Ruby y Lisp, pero no en Julia, y esa diferencia es en realidad una pista falsa. El hecho de que los símbolos estén internados, es decir, procesados por la implementación del lenguaje para comparaciones rápidas de igualdad, también es un detalle de implementación irrelevante. Podría tener una implementación que no incluya símbolos internos y el lenguaje sería exactamente el mismo.
Entonces, ¿qué es realmente un símbolo? La respuesta radica en algo que Julia y Lisp tienen en común: la capacidad de representar el código del lenguaje como una estructura de datos en el propio lenguaje. Algunas personas llaman a esto "homoiconicidad" ( Wikipedia ), pero otros no parecen pensar que solo es suficiente para que un idioma sea homicónico. Pero la terminología realmente no importa. El punto es que cuando un lenguaje puede representar su propio código, necesita una forma de representar cosas como asignaciones, llamadas a funciones, cosas que pueden escribirse como valores literales, etc. También necesita una forma de representar sus propias variables. Es decir, necesita una forma de representar, como datos, el foo
lado izquierdo de esto:
foo == "foo"
Ahora estamos llegando al meollo del asunto: la diferencia entre un símbolo y una cadena es la diferencia entre foo
el lado izquierdo de esa comparación y "foo"
el lado derecho. A la izquierda, foo
hay un identificador y evalúa el valor vinculado a la variable foo
en el ámbito actual. A la derecha, "foo"
es un literal de cadena y se evalúa como el valor de cadena "foo". Un símbolo tanto en Lisp como en Julia es cómo se representa una variable como datos. Una cadena solo se representa a sí misma. Puede ver la diferencia aplicándoles eval
:
julia> eval(:foo)
ERROR: foo not defined
julia> foo = "hello"
"hello"
julia> eval(:foo)
"hello"
julia> eval("foo")
"foo"
Lo que :foo
evalúa el símbolo depende de a qué, en todo caso, foo
está vinculada la variable , mientras que "foo"
siempre se evalúa como "foo". Si desea construir expresiones en Julia que usan variables, entonces está usando símbolos (lo sepa o no). Por ejemplo:
julia> ex = :(foo = "bar")
:(foo = "bar")
julia> dump(ex)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol foo
2: String "bar"
typ: Any
Lo que eso muestra, entre otras cosas, es que hay un :foo
objeto de símbolo dentro del objeto de expresión que obtienes citando el código foo = "bar"
. Aquí hay otro ejemplo, construyendo una expresión con el símbolo :foo
almacenado en la variable sym
:
julia> sym = :foo
:foo
julia> eval(sym)
"hello"
julia> ex = :($sym = "bar"; 1 + 2)
:(begin
foo = "bar"
1 + 2
end)
julia> eval(ex)
3
julia> foo
"bar"
Si intenta hacer esto cuando sym
está vinculado a la cadena "foo"
, no funcionará:
julia> sym = "foo"
"foo"
julia> ex = :($sym = "bar"; 1 + 2)
:(begin
"foo" = "bar"
1 + 2
end)
julia> eval(ex)
ERROR: syntax: invalid assignment location ""foo""
Es bastante claro ver por qué esto no funcionará: si trató de asignar "foo" = "bar"
a mano, tampoco funcionará.
Esta es la esencia de un símbolo: un símbolo se utiliza para representar una variable en la metaprogramación. Una vez que tenga símbolos como tipo de datos, por supuesto, se vuelve tentador usarlos para otras cosas, como las teclas hash. Pero ese es un uso incidental y oportunista de un tipo de datos que tiene otro propósito principal.
Tenga en cuenta que dejé de hablar de Ruby hace un tiempo. Esto se debe a que Ruby no es homoicónico: Ruby no representa sus expresiones como objetos Ruby. Entonces, el tipo de símbolo de Ruby es una especie de órgano vestigial: una adaptación sobrante, heredada de Lisp, pero que ya no se usa para su propósito original. Los símbolos de Ruby se han cooptado para otros fines, como claves hash, para extraer métodos de las tablas de métodos, pero los símbolos en Ruby no se usan para representar variables.
En cuanto a por qué los símbolos se usan en DataFrames en lugar de cadenas, es porque es un patrón común en DataFrames vincular los valores de columna a las variables dentro de las expresiones proporcionadas por el usuario. Por lo tanto, es natural que los nombres de columna sean símbolos, ya que los símbolos son exactamente lo que usa para representar las variables como datos. Actualmente, tiene que escribir df[:foo]
para acceder a la foo
columna, pero en el futuro, puede acceder a ella como en su df.foo
lugar. Cuando eso sea posible, solo las columnas cuyos nombres son identificadores válidos serán accesibles con esta conveniente sintaxis.
Ver también: