Що таке "символ" у Джулії?


131

Зокрема: я намагаюся використовувати пакет даних DataFrames Julia, зокрема функцію readtable () з опцією імена, але для цього потрібен вектор символів.

  • що таке символ?
  • чому б вони обрали це над вектором струн?

Поки що я знайшов лише кілька посилань на символ слова в мові Джулія. Здається, символи представлені символом ": var", але мені далеко не ясно, що вони є.

Убік: я можу бігати

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

Мої два запитувані питання досі стоять.


3
Деякі розмови на цю тему можна знайти тут: groups.google.com/d/msg/julia-users/MS7KW8IU-0o/cQ-yDOs_CQEJ
jverzani

Відповіді:


231

Символи у Джулії такі ж, як у Ліспа, Схеми або Рубі. Однак, на мою думку , відповіді на ці пов'язані питання не дуже задоволені . Якщо ви читаєте ці відповіді, то здається, що причина символу інша, ніж рядок, полягає в тому, що рядки є змінними, тоді як символи незмінні, а символи також "інтерновані" - що б це не означало. Струни в Рубі та Ліспі бувають непомітними, але їх немає у Джулії, і ця різниця насправді є червоною оселедець. Те, що символи інтерновані - тобто хешировані мовою впровадження для швидкого порівняння рівності - також є неактуальною деталлю реалізації. У вас може бути реалізація, яка не інтернує символи, і мова буде абсолютно однаковою.

Отже, що насправді є символом? Відповідь полягає у чомусь спільному Джулії та Лісп - здатності представляти код мови як структуру даних у самій мові. Деякі люди називають це "гомоніконічністю" ( Вікіпедія ), але інші, здається, не вважають, що однієї достатньо для того, щоб мова була гомоніконічною. Але термінологія насправді не має значення. Справа в тому, що коли мова може представляти власний код, їй потрібен спосіб представлення речей, таких як призначення, виклики функцій, речі, які можна записати як буквальні значення тощо. Також він потребує способу представлення власних змінних. Тобто вам потрібен спосіб представити - як дані - 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натомість. Коли це стане можливим, до цього зручного синтаксису будуть доступні лише стовпці, імена яких є дійсними ідентифікаторами.

Дивитися також:


6
Інтернування: в інформатиці струнне інтернування - це метод зберігання лише однієї копії кожного окремого рядкового значення, яке повинно бути незмінним. Інтернування рядків робить деякі завдання обробці рядків більш ефективними в часі або просторі за рахунок необхідності більше часу при створенні або інтернуванні рядка. en.wikipedia.org/wiki/String_interning
xiaodai

В один момент ви пишете, eval(:foo)а в інший eval(sym). Чи є змістовна різниця між eval(:foo)і eval(foo)?
Відтінки сірого

Дуже так: eval(:foo)дає значення, до якого змінна fooпов'язана, тоді як eval(foo)виклики прирівнюються до цього значення. Писання eval(:foo)еквівалентно справедливому foo(в глобальному масштабі), так eval(foo)це як eval(eval(:foo)).
Стефан Карпінський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.