Les symboles dans Julia sont les mêmes que dans Lisp, Scheme ou Ruby. Cependant, les réponses à ces questions connexes ne sont pas vraiment satisfaisantes , à mon avis. Si vous lisez ces réponses, il semble que la raison pour laquelle un symbole est différent d'une chaîne est que les chaînes sont mutables tandis que les symboles sont immuables, et que les symboles sont également «internés» - quoi que cela signifie. Il se trouve que les chaînes sont mutables dans Ruby et Lisp, mais elles ne le sont pas dans Julia, et cette différence est en fait un hareng rouge. Le fait que les symboles soient internés - c'est-à-dire hachés par l'implémentation du langage pour des comparaisons d'égalité rapides - est également un détail d'implémentation non pertinent. Vous pourriez avoir une implémentation qui n'intègre pas de symboles et le langage serait exactement le même.
Alors, qu'est-ce qu'un symbole, vraiment? La réponse réside dans quelque chose que Julia et Lisp ont en commun - la capacité de représenter le code du langage comme une structure de données dans le langage lui-même. Certaines personnes appellent cela «homoiconicité» ( Wikipedia ), mais d'autres ne semblent pas penser que cela suffit à lui seul pour qu'une langue soit homoïconique. Mais la terminologie n'a pas vraiment d'importance. Le fait est que lorsqu'un langage peut représenter son propre code, il a besoin d'un moyen de représenter des choses comme des affectations, des appels de fonction, des choses qui peuvent être écrites comme des valeurs littérales, etc. Il a également besoin d'un moyen de représenter ses propres variables. Ie, vous avez besoin d'un moyen de représenter - sous forme de données - le foo
sur le côté gauche de ceci:
foo == "foo"
Nous entrons maintenant dans le vif du sujet: la différence entre un symbole et une chaîne est la différence entre foo
le côté gauche de cette comparaison et "foo"
le côté droit. Sur la gauche, se foo
trouve un identificateur et il évalue la valeur liée à la variable foo
dans la portée actuelle. Sur la droite, se "foo"
trouve un littéral de chaîne et il évalue la valeur de chaîne "foo". Un symbole dans Lisp et Julia est la façon dont vous représentez une variable sous forme de données. Une chaîne se représente simplement. Vous pouvez voir la différence en appliquant eval
à eux:
julia> eval(:foo)
ERROR: foo not defined
julia> foo = "hello"
"hello"
julia> eval(:foo)
"hello"
julia> eval("foo")
"foo"
Ce que le symbole :foo
évalue dépend de ce à quoi - le cas échéant - la variable foo
est liée, alors que "foo"
toujours évalue juste à "foo". Si vous souhaitez créer des expressions dans Julia qui utilisent des variables, vous utilisez des symboles (que vous le sachiez ou non). Par exemple:
julia> ex = :(foo = "bar")
:(foo = "bar")
julia> dump(ex)
Expr
head: Symbol =
args: Array{Any}((2,))
1: Symbol foo
2: String "bar"
typ: Any
Ce que cela montre, entre autres, c'est qu'il y a un :foo
objet symbole à l'intérieur de l'objet d'expression que vous obtenez en citant le code foo = "bar"
. Voici un autre exemple, construction d'une expression avec le symbole :foo
stocké dans 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 vous essayez de le faire quand sym
est lié à la chaîne "foo"
, cela ne fonctionnera pas:
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""
Il est assez clair de voir pourquoi cela ne fonctionnera pas - si vous avez essayé d'attribuer "foo" = "bar"
manuellement, cela ne fonctionnera pas non plus.
C'est l'essence d'un symbole: un symbole est utilisé pour représenter une variable en métaprogrammation. Une fois que vous avez des symboles comme type de données, bien sûr, il devient tentant de les utiliser pour d'autres choses, comme des clés de hachage. Mais c'est une utilisation fortuite et opportuniste d'un type de données qui a un autre objectif principal.
Notez que j'ai arrêté de parler de Ruby il y a quelque temps. C'est parce que Ruby n'est pas homoiconique: Ruby ne représente pas ses expressions comme des objets Ruby. Le type de symbole de Ruby est donc une sorte d'organe résiduel - une adaptation restante, héritée de Lisp, mais qui n'est plus utilisée pour son objectif initial. Les symboles Ruby ont été cooptés à d'autres fins - en tant que clés de hachage, pour extraire des méthodes des tables de méthodes - mais les symboles en Ruby ne sont pas utilisés pour représenter des variables.
Quant à savoir pourquoi les symboles sont utilisés dans les DataFrames plutôt que les chaînes, c'est parce que c'est un modèle commun dans DataFrames pour lier les valeurs de colonne à des variables à l'intérieur des expressions fournies par l'utilisateur. Il est donc naturel que les noms de colonnes soient des symboles, car les symboles sont exactement ce que vous utilisez pour représenter des variables sous forme de données. Actuellement, vous devez écrire df[:foo]
pour accéder à la foo
colonne, mais à l'avenir, vous pourrez peut-être y accéder à la df.foo
place. Lorsque cela devient possible, seules les colonnes dont les noms sont des identificateurs valides seront accessibles avec cette syntaxe pratique.
Voir également: