Apa itu "simbol" dalam Julia?


131

Secara khusus: Saya mencoba menggunakan paket DataFrames Julia, khususnya fungsi readtable () dengan opsi nama, tetapi itu membutuhkan vektor simbol.

  • apa itu simbol?
  • mengapa mereka memilih itu daripada vektor string?

Sejauh ini saya hanya menemukan beberapa referensi untuk simbol kata dalam bahasa Julia. Tampaknya simbol diwakili oleh ": var", tetapi jauh dari jelas bagi saya apa itu.

Selain itu, saya bisa lari

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

Dua pertanyaan saya masih ada.


3
Beberapa percakapan tentang topik ini dapat ditemukan di sini: groups.google.com/d/msg/julia-users/MS7KW8IU-0o/cQ-yDOs_CQEJ
jverzani

Jawaban:


231

Simbol di Julia sama dengan di Lisp, Skema atau Ruby. Namun, jawaban atas pertanyaan - pertanyaan terkait tidak benar-benar memuaskan , menurut saya. Jika Anda membaca jawaban-jawaban itu, tampaknya alasan suatu simbol berbeda dari string adalah bahwa string dapat berubah sementara simbol tidak dapat diubah, dan simbol juga "diinternir" - apa pun artinya. String memang bisa berubah di Ruby dan Lisp, tetapi mereka tidak di Julia, dan perbedaan itu sebenarnya adalah ikan haring merah. Fakta bahwa simbol diinternir - yaitu hash oleh implementasi bahasa untuk perbandingan kesetaraan cepat - juga merupakan detail implementasi yang tidak relevan. Anda bisa memiliki implementasi yang tidak menggunakan simbol dan bahasanya akan sama persis.

Jadi, apa itu simbol? Jawabannya terletak pada sesuatu yang dimiliki oleh Julia dan Lisp - kemampuan untuk mewakili kode bahasa sebagai struktur data dalam bahasa itu sendiri. Beberapa orang menyebut ini "homoiconicity" ( Wikipedia ), tetapi yang lain tampaknya tidak menganggap itu saja sudah cukup untuk sebuah bahasa menjadi homoiconic. Tetapi terminologinya tidak terlalu penting. Intinya adalah bahwa ketika suatu bahasa dapat merepresentasikan kodenya sendiri, ia membutuhkan cara untuk mewakili hal-hal seperti penugasan, pemanggilan fungsi, hal-hal yang dapat dituliskan sebagai nilai literal, dll. Ia juga membutuhkan cara untuk mewakili variabelnya sendiri. Yaitu, Anda perlu cara untuk mewakili - sebagai data - foodi sisi kiri ini:

foo == "foo"

Sekarang kita sampai pada inti permasalahan: perbedaan antara simbol dan string adalah perbedaan antara foodi sisi kiri perbandingan itu dan "foo"di sisi kanan. Di sebelah kiri, fooadalah pengidentifikasi dan mengevaluasi nilai terikat ke variabel foodalam lingkup saat ini. Di sebelah kanan, "foo"adalah string literal dan mengevaluasi ke nilai string "foo". Simbol di Lisp dan Julia adalah cara Anda merepresentasikan variabel sebagai data. Sebuah string hanya mewakili dirinya sendiri. Anda dapat melihat perbedaannya dengan menerapkannya evalpada mereka:

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

julia> foo = "hello"
"hello"

julia> eval(:foo)
"hello"

julia> eval("foo")
"foo"

Apa yang :foodievaluasi simbol tergantung pada apa - jika ada - variabel footerikat, sedangkan "foo"selalu hanya mengevaluasi ke "foo". Jika Anda ingin membuat ekspresi dalam Julia yang menggunakan variabel, maka Anda menggunakan simbol (apakah Anda mengetahuinya atau tidak). Sebagai contoh:

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

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

Apa yang ditunjukkan barang yang dibuang, antara lain, adalah bahwa ada :fooobjek simbol di dalam objek ekspresi yang Anda dapatkan dengan mengutip kode foo = "bar". Berikut contoh lain, membangun ekspresi dengan simbol yang :foodisimpan dalam variabel 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"

Jika Anda mencoba melakukan ini ketika symterikat pada string "foo", itu tidak akan berfungsi:

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

Cukup jelas untuk melihat mengapa ini tidak berhasil - jika Anda mencoba menetapkan "foo" = "bar"dengan tangan, itu juga tidak akan berhasil.

Ini adalah esensi dari simbol: simbol digunakan untuk mewakili variabel dalam metaprogramming. Setelah Anda memiliki simbol sebagai tipe data, tentu saja, tergoda untuk menggunakannya untuk hal-hal lain, seperti kunci hash. Tapi itu penggunaan insidental, oportunistik dari tipe data yang memiliki tujuan utama lain.

Perhatikan bahwa saya berhenti berbicara tentang Ruby beberapa waktu lalu. Itu karena Ruby bukan homoikonik: Ruby tidak mewakili ekspresinya sebagai objek Ruby. Jadi tipe simbol Ruby adalah jenis organ sisa - adaptasi sisa, diwarisi dari Lisp, tetapi tidak lagi digunakan untuk tujuan aslinya. Simbol-simbol Ruby telah dikooptasi untuk keperluan lain - sebagai kunci hash, untuk menarik metode dari tabel metode - tetapi simbol-simbol di Ruby tidak digunakan untuk mewakili variabel.

Mengenai mengapa simbol digunakan dalam DataFrames daripada string, itu karena itu merupakan pola umum dalam DataFrames untuk mengikat nilai kolom ke variabel di dalam ekspresi yang disediakan pengguna. Jadi wajar jika nama kolom menjadi simbol, karena simbol adalah apa yang Anda gunakan untuk mewakili variabel sebagai data. Saat ini, Anda harus menulis df[:foo]untuk mengakses fookolom, tetapi di masa mendatang, Anda mungkin dapat mengaksesnya sebagai df.foogantinya. Ketika itu menjadi mungkin, hanya kolom yang namanya pengidentifikasi valid yang dapat diakses dengan sintaksis yang mudah digunakan ini.

Lihat juga:


6
Interning: Dalam ilmu komputer, string interning adalah metode menyimpan hanya satu salinan dari masing-masing nilai string yang berbeda, yang harus tidak berubah. Interning string membuat beberapa tugas pemrosesan string lebih hemat waktu atau ruang dengan biaya yang membutuhkan lebih banyak waktu ketika string dibuat atau diinternir. en.wikipedia.org/wiki/String_interning
xiaodai

Pada satu titik Anda menulis eval(:foo)dan di titik lain eval(sym). Apakah ada perbedaan yang bermakna antara eval(:foo)dan eval(foo)?
Grayscale

Sangat banyak: eval(:foo)memberikan nilai yang footerikat variabel sedangkan eval(foo)panggilan eval pada nilai itu. Menulis eval(:foo)sama dengan adil foo(dalam lingkup global) demikian eval(foo)juga eval(eval(:foo)).
StefanKarpinski
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.