"สัญลักษณ์" ใน Julia คืออะไร?


133

โดยเฉพาะ: ฉันพยายามใช้แพ็คเกจ 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

คำตอบ:


233

สัญลักษณ์ใน Julia จะเหมือนกับใน Lisp, Scheme หรือ Ruby อย่างไรก็ตามในความคิดของฉันคำตอบสำหรับคำถามที่เกี่ยวข้องนั้นไม่เป็นที่น่าพอใจนัก หากคุณอ่านคำตอบเหล่านั้นดูเหมือนว่าสาเหตุที่สัญลักษณ์แตกต่างจากสตริงก็คือสตริงนั้นไม่แน่นอนในขณะที่สัญลักษณ์ไม่เปลี่ยนรูปและสัญลักษณ์ยังเป็น "ภายใน" ไม่ว่าจะหมายถึงอะไรก็ตาม สตริงเกิดขึ้นได้ใน Ruby และ Lisp แต่ไม่ได้อยู่ใน Julia และความแตกต่างนั้นเป็นปลาเฮอริ่งสีแดง ความจริงที่ว่าสัญลักษณ์ถูก จำกัด ไว้ - นั่นคือการแฮชโดยการใช้ภาษาเพื่อการเปรียบเทียบความเท่าเทียมกันอย่างรวดเร็ว - ยังเป็นรายละเอียดการใช้งานที่ไม่เกี่ยวข้อง คุณสามารถนำไปใช้งานที่ไม่มีสัญลักษณ์ฝึกงานและภาษาจะเหมือนกันทุกประการ

แล้วสัญลักษณ์คืออะไร? คำตอบอยู่ที่สิ่งที่ Julia และ Lisp มีเหมือนกันนั่นคือความสามารถในการแสดงรหัสของภาษาเป็นโครงสร้างข้อมูลในภาษานั้นเอง บางคนเรียกสิ่งนี้ว่า "homoiconicity" ( Wikipedia ) แต่บางคนดูเหมือนจะไม่คิดว่าภาษาเดียวก็เพียงพอแล้วสำหรับภาษาที่จะเป็น homoiconic แต่ศัพท์มันไม่สำคัญหรอก ประเด็นก็คือเมื่อภาษาสามารถแทนรหัสของตัวเองได้จำเป็นต้องมีวิธีในการแสดงสิ่งต่างๆเช่นการกำหนดการเรียกใช้ฟังก์ชันสิ่งที่สามารถเขียนเป็นค่าตามตัวอักษร ฯลฯ นอกจากนี้ยังต้องการวิธีในการแทนตัวแปรของตัวเอง กล่าวคือคุณต้องมีวิธีแสดง - เป็นข้อมูล - fooทางด้านซ้ายมือของสิ่งนี้:

foo == "foo"

ตอนนี้เรามาถึงหัวใจของเรื่องนี้: ความแตกต่างระหว่างสัญลักษณ์และสตริงคือความแตกต่างระหว่างfooทางด้านซ้ายมือของการเปรียบเทียบนั้นและ"foo"ทางด้านขวามือ ทางด้านซ้ายfooเป็นตัวระบุและประเมินเป็นค่าที่ผูกไว้กับตัวแปรfooในขอบเขตปัจจุบัน ทางด้านขวา"foo"คือสตริงลิเทอรัลและประเมินเป็นค่าสตริง "foo" สัญลักษณ์ทั้งใน Lisp และ Julia คือวิธีที่คุณแสดงตัวแปรเป็นข้อมูล สตริงแสดงถึงตัวมันเอง คุณสามารถเห็นความแตกต่างได้โดยใช้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"ด้วยมือก็จะไม่ได้ผลเช่นกัน

นี่คือสาระสำคัญของสัญลักษณ์: สัญลักษณ์ใช้แทนตัวแปรใน metaprogramming เมื่อคุณมีสัญลักษณ์เป็นประเภทข้อมูลแน่นอนว่ามันจะดึงดูดให้ใช้กับสิ่งอื่น ๆ เช่นเป็นแฮชคีย์ แต่นั่นเป็นการใช้ประเภทข้อมูลโดยบังเอิญและฉวยโอกาสซึ่งมีวัตถุประสงค์หลักอื่น

สังเกตว่าฉันเลิกพูดถึง Ruby ไปสักพักแล้ว นั่นเป็นเพราะ Ruby ไม่ใช่ homoiconic: Ruby ไม่ได้แสดงนิพจน์เป็นวัตถุ Ruby ประเภทสัญลักษณ์ของรูบี้จึงเป็นอวัยวะร่องรอยซึ่งเป็นสิ่งดัดแปลงที่เหลือสืบทอดมาจากลิสป์ แต่ไม่ได้ใช้เพื่อจุดประสงค์เดิมอีกต่อไป สัญลักษณ์ Ruby ได้รับการเลือกร่วมกันเพื่อวัตถุประสงค์อื่นเช่นแฮชคีย์เพื่อดึงเมธอดออกจากตารางวิธีการ - แต่สัญลักษณ์ใน Ruby ไม่ได้ใช้เพื่อแสดงตัวแปร

สาเหตุที่ใช้สัญลักษณ์ใน DataFrames แทนที่จะเป็นสตริงนั้นเป็นเพราะรูปแบบทั่วไปใน DataFrames เพื่อผูกค่าคอลัมน์กับตัวแปรภายในนิพจน์ที่ผู้ใช้กำหนด ดังนั้นจึงเป็นเรื่องธรรมดาที่ชื่อคอลัมน์จะเป็นสัญลักษณ์เนื่องจากสัญลักษณ์เป็นสิ่งที่คุณใช้แทนตัวแปรเป็นข้อมูล ขณะนี้คุณต้องเขียนdf[:foo]เพื่อเข้าถึงfooคอลัมน์ แต่ในอนาคตคุณอาจสามารถเข้าถึงได้df.fooแทน เมื่อเป็นไปได้เฉพาะคอลัมน์ที่มีชื่อเป็นตัวระบุที่ถูกต้องเท่านั้นที่สามารถเข้าถึงได้ด้วยไวยากรณ์ที่สะดวกนี้

ดูสิ่งนี้ด้วย:


6
Interning: ในวิทยาการคอมพิวเตอร์การฝึกงานแบบสตริงเป็นวิธีการจัดเก็บสำเนาเพียงหนึ่งชุดของค่าสตริงที่แตกต่างกันซึ่งจะต้องไม่เปลี่ยนรูป สตริงที่เชื่อมต่อกันทำให้งานประมวลผลสตริงบางงานประหยัดเวลาหรือใช้พื้นที่ได้มากขึ้นด้วยต้นทุนที่ต้องใช้เวลามากขึ้นในการสร้างสตริงหรือภายใน en.wikipedia.org/wiki/String_interning
xiaodai

เมื่อถึงจุดหนึ่งที่คุณเขียนและที่อื่นeval(:foo) eval(sym)มีความหมายที่แตกต่างระหว่างeval(:foo)และeval(foo)?
Grayscale

1
เป็นอย่างมาก: eval(:foo)ให้ค่าที่ตัวแปรfooถูกผูกไว้ในขณะที่การeval(foo)เรียกใช้ประเมินค่านั้น การเขียนeval(:foo)เทียบเท่ากับเพียงfoo(ในขอบเขตทั่วโลก) ดังนั้นจึงeval(foo)เป็นเช่นeval(eval(:foo))นั้น
StefanKarpinski
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.