Что такое "символ" у Юлии?

В частности: я пытаюсь использовать пакет DataFrames Джулии, в частности функцию readtable() с опцией names, но для этого требуется вектор символов.

  • что такое символ?
  • почему они выбирают это по вектору строк?

До сих пор я нашел лишь несколько ссылок на символ слова в языке Юлия. Кажется, что символы представлены как ":var", но мне далеко не ясно, что они собой представляют.

В сторону: я могу бежать

df = readtable( "table.txt", names = [symbol("var1"), symbol("var2")] )

Мои два маркированных вопроса все еще стоят.

1 ответ

Решение

Символы в Julia такие же, как в Lisp, Scheme или Ruby. Однако, на мой взгляд, ответы на эти смежные вопросы не совсем удовлетворительные. Если вы читаете эти ответы, кажется, что причина, по которой символ отличается от строки, состоит в том, что строки являются изменяемыми, в то время как символы неизменяемы, а символы также "интернированы" - что бы это ни значило. Строки действительно изменчивы в Ruby и Lisp, но их нет в Julia, и эта разница на самом деле является красной сельдью. Тот факт, что символы интернированы - т.е. хешируется языковой реализацией для быстрых сравнений на равенство - также не имеет значения для реализации. Вы можете иметь реализацию, которая не интернирует символы, и язык будет точно таким же.

Так что же такое символ на самом деле? Ответ заключается в том, что объединяет Джулию и Лисп - способность представлять код языка как структуру данных в самом языке. Некоторые люди называют это "гомойконичностью" ( Википедия), но другие, кажется, не думают, что одного языка достаточно для того, чтобы язык был гомойконичным. Но терминология на самом деле не имеет значения. Дело в том, что когда язык может представлять свой собственный код, ему нужен способ представления таких вещей, как присваивания, вызовы функций, вещи, которые можно записать в виде буквальных значений, и т. Д. Ему также нужен способ представления своих собственных переменных. То есть вам нужен способ представления - в качестве данных - foo на левой стороне этого:

foo == "foo"

Теперь мы подошли к сути вопроса: разница между символом и строкой - это разница между foo на левой стороне этого сравнения и "foo" на правой стороне. Налево, foo является идентификатором, и он оценивается в значение, связанное с переменной foo в текущем объеме. Справа, "foo" является строковым литералом, и он оценивается как строковое значение "foo". Символ как в Лиспе, так и в Юлии - это то, как вы представляете переменную как данные. Строка просто представляет себя. Вы можете увидеть разницу, применив eval им:

julia> eval(:foo)
ERROR: foo not defined

julia> foo = "hello"
"hello"

julia> eval(:foo)
"hello"

julia> eval("foo")
"foo"

Какой символ :foo оценивает, зависит от того, что - если что-нибудь - переменная foo связан, тогда как "foo" всегда просто оценивает "foo". Если вы хотите построить выражения в Julia, которые используют переменные, то вы используете символы (знаете ли вы это или нет). Например:

julia> ex = :(foo = "bar")
:(foo = "bar")

julia> dump(ex)
Expr
  head: Symbol =
  args: Array{Any}((2,))
    1: Symbol foo
    2: String "bar"
  typ: Any

То, что вывалили из всего этого, показывает, среди прочего, что есть :foo объект символа внутри объекта выражения, который вы получаете, цитируя код foo = "bar", Вот еще один пример, построение выражения с символом :foo хранится в переменной 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"

Если вы попытаетесь сделать это, когда sym привязан к строке "foo" не сработает

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""

Довольно понятно, почему это не сработает - если вы попытались назначить "foo" = "bar" вручную это тоже не сработает.

В этом суть символа: символ используется для представления переменной в метапрограммировании. Разумеется, когда у вас есть символы в качестве типа данных, становится заманчивым использовать их для других целей, например, в качестве хеш-ключей. Но это случайное, оппортунистическое использование типа данных, имеющего другую основную цель.

Обратите внимание, что я перестал говорить о Руби некоторое время назад. Это потому, что Ruby не гомоичен: Ruby не представляет свои выражения как объекты Ruby. Таким образом, символьный тип Руби является своего рода рудиментарным органом - оставшейся адаптацией, унаследованной от Лиспа, но более не используемой для его первоначальной цели. Символы Ruby использовались для других целей - в качестве ключей хеширования, для извлечения методов из таблиц методов - но символы в Ruby не используются для представления переменных.

Что касается того, почему символы используются в DataFrames, а не в строках, то это потому, что в DataFrames распространена схема связывания значений столбцов с переменными внутри пользовательских выражений. Поэтому имена столбцов являются символами, поскольку символы представляют собой именно то, что вы используете для представления переменных в виде данных. В настоящее время вы должны написать df[:foo] чтобы получить доступ к foo столбец, но в будущем вы сможете получить к нему доступ как df.foo вместо. Когда это станет возможным, с этим удобным синтаксисом будут доступны только столбцы, имена которых являются действительными идентификаторами.

Смотрите также:

Что касается исходного вопроса на данный момент, то есть версии 0.21 (и в будущем) DataFrames.jl позволяет как Symbols и строки, которые будут использоваться в качестве имен столбцов, так как это не проблема для поддержки обоих и в разных ситуациях либо Symbol или строка может быть предпочтительнее для пользователя.

Вот пример:

julia> using DataFrames

julia> df = DataFrame(:a => 1:2, :b => 3:4)
2×2 DataFrame
│ Row │ a     │ b     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 3     │
│ 2   │ 2     │ 4     │

julia> DataFrame("a" => 1:2, "b" => 3:4) # this is the same
2×2 DataFrame
│ Row │ a     │ b     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 3     │
│ 2   │ 2     │ 4     │

julia> df[:, :a]
2-element Array{Int64,1}:
 1
 2

julia> df[:, "a"] # this is the same
2-element Array{Int64,1}:
 1
 2
Другие вопросы по тегам