Os símbolos em Julia são os mesmos que em Lisp, Scheme ou Ruby. No entanto, na minha opinião , as respostas a essas perguntas relacionadas não são realmente satisfatórias . Se você ler essas respostas, parece que a razão pela qual um símbolo é diferente de uma string é que as strings são mutáveis, enquanto os símbolos são imutáveis e os símbolos também são "internados" - o que quer que isso signifique. As strings são mutáveis em Ruby e Lisp, mas elas não estão em Julia, e essa diferença é realmente um arenque vermelho. O fato de os símbolos serem internados - isto é, hash pela implementação da linguagem para comparações rápidas de igualdade - também é um detalhe irrelevante da implementação. Você pode ter uma implementação que não armazene símbolos e o idioma seria exatamente o mesmo.
Então, o que é realmente um símbolo? A resposta está em algo que Julia e Lisp têm em comum - a capacidade de representar o código da linguagem como uma estrutura de dados na própria linguagem. Algumas pessoas chamam isso de "homoiconicidade" ( Wikipedia ), mas outras não parecem pensar que isso seja suficiente para que um idioma seja homoicônico. Mas a terminologia realmente não importa. O ponto é que, quando uma linguagem pode representar seu próprio código, ela precisa de uma maneira de representar coisas como atribuições, chamadas de função, coisas que podem ser escritas como valores literais etc. Ela também precisa de uma maneira de representar suas próprias variáveis. Ou seja, você precisa de uma maneira de representar - como dados - o foo
lado esquerdo disso:
foo == "foo"
Agora estamos chegando ao cerne da questão: a diferença entre um símbolo e uma string é a diferença entre foo
o lado esquerdo dessa comparação e "foo"
o lado direito. À esquerda, foo
há um identificador e ele avalia o valor associado à variável foo
no escopo atual. À direita, "foo"
é uma string literal e avalia o valor da string "foo". Um símbolo no Lisp e na Julia é como você representa uma variável como dados. Uma string apenas representa a si mesma. Você pode ver a diferença aplicando eval
a eles:
julia> eval(:foo)
ERROR: foo not defined
julia> foo = "hello"
"hello"
julia> eval(:foo)
"hello"
julia> eval("foo")
"foo"
O que o símbolo :foo
avalia depende de qual - ou alguma coisa - a variável foo
está vinculada, enquanto "foo"
sempre apenas avalia como "foo". Se você deseja construir expressões em Julia que usam variáveis, então você está usando símbolos (se você conhece ou não). Por exemplo:
julia> ex = :(foo = "bar")
:(foo = "bar")
julia> dump(ex)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol foo
2: String "bar"
typ: Any
O que esse material despejado mostra, entre outras coisas, é que há um :foo
objeto de símbolo dentro do objeto de expressão que você obtém citando o código foo = "bar"
. Aqui está outro exemplo, construindo uma expressão com o símbolo :foo
armazenado na variável 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"
Se você tentar fazer isso quando sym
estiver vinculado à string "foo"
, não 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""
É bem claro para ver por que isso não funcionará - se você tentou atribuir "foo" = "bar"
manualmente, também não funcionará.
Esta é a essência de um símbolo: um símbolo é usado para representar uma variável na metaprogramação. Depois de ter símbolos como um tipo de dados, é claro, torna-se tentador usá-los para outras coisas, como chaves de hash. Mas esse é um uso casual e oportunista de um tipo de dados que tem outro objetivo principal.
Note que eu parei de falar sobre Ruby há um tempo. Isso ocorre porque Ruby não é homoicônico: Ruby não representa suas expressões como objetos Ruby. Portanto, o tipo de símbolo de Ruby é uma espécie de órgão vestigial - uma adaptação restante, herdada de Lisp, mas não mais usada para seu propósito original. Os símbolos Ruby foram cooptados para outros fins - como chaves de hash, para extrair métodos das tabelas de métodos - mas os símbolos no Ruby não são usados para representar variáveis.
Quanto ao motivo pelo qual os símbolos são usados nos DataFrames, e não nas cadeias, é porque é um padrão comum nos DataFrames vincular valores de colunas a variáveis dentro de expressões fornecidas pelo usuário. Portanto, é natural que os nomes das colunas sejam símbolos, pois os símbolos são exatamente o que você usa para representar variáveis como dados. Atualmente, você precisa escrever df[:foo]
para acessar a foo
coluna, mas, no futuro, poderá acessá-la como df.foo
alternativa. Quando isso se tornar possível, apenas as colunas cujos nomes são identificadores válidos estarão acessíveis com esta sintaxe conveniente.
Veja também: