เหตุใด Clojure จึงมี "คำหลัก" นอกเหนือจาก "สัญลักษณ์"


130

ฉันมีความรู้เกี่ยวกับ Lisps อื่น ๆ (โดยเฉพาะโครงการ) จากทางกลับ เร็ว ๆ นี้ผมได้อ่านเกี่ยวกับClojure ฉันเห็นว่ามันมีทั้ง "สัญลักษณ์" และ "คีย์เวิร์ด" สัญลักษณ์ที่ฉันคุ้นเคย แต่ไม่ใช่กับคำหลัก

Lisps คนอื่นมีคีย์เวิร์ดไหม คีย์เวิร์ดแตกต่างจากสัญลักษณ์อื่นที่ไม่ใช่สัญกรณ์ต่างกันอย่างไร (เช่นโคลอน)


คำตอบ:


139

นี่คือเอกสาร Clojureสำหรับคำหลักและสัญลักษณ์

คีย์เวิร์ดคือตัวระบุเชิงสัญลักษณ์ที่ประเมินตัวเอง พวกเขาให้การทดสอบความเท่าเทียมที่รวดเร็วมาก ...

สัญลักษณ์คือตัวระบุที่ปกติใช้เพื่ออ้างถึงสิ่งอื่น สามารถใช้ในรูปแบบโปรแกรมเพื่ออ้างถึงพารามิเตอร์ฟังก์ชันให้การผูกชื่อคลาสและตัวแปรส่วนกลาง ...

โดยทั่วไปคำหลักมักใช้เป็น "สตริงคงที่" ที่มีน้ำหนักเบาเช่นสำหรับคีย์ของแผนที่แฮชหรือค่าการจัดส่งของหลายวิธี โดยทั่วไปสัญลักษณ์จะใช้เพื่อตั้งชื่อตัวแปรและฟังก์ชั่นและเป็นเรื่องปกติน้อยที่จะจัดการให้เป็นวัตถุโดยตรงยกเว้นในมาโครและอื่น ๆ แต่ไม่มีอะไรหยุดคุณจากการใช้สัญลักษณ์ทุกที่ที่คุณใช้คำหลัก (หากคุณไม่สนใจที่จะอ้างถึงมันตลอดเวลา)

วิธีที่ง่ายที่สุดในการดูความแตกต่างคือการอ่านKeyword.javaและSymbol.javaในแหล่งข้อมูล Clojure มีความแตกต่างในการใช้งานที่ชัดเจนเล็กน้อย ตัวอย่างเช่นสัญลักษณ์ใน Clojure สามารถมีข้อมูลเมตาและคำหลักต้องไม่ได้

นอกเหนือจากไวยากรณ์ single-colon แล้วคุณยังสามารถใช้ double-colon เพื่อสร้างคีย์เวิร์ดที่ตรงตามเนมสเปซได้

user> :foo
:foo
user> ::foo
:user/foo

Common Lisp มีคีย์เวิร์ดเช่นเดียวกับ Ruby และภาษาอื่น ๆ แน่นอนว่าภาษาเหล่านั้นแตกต่างกันเล็กน้อย ความแตกต่างบางประการระหว่างคำหลัก Lisp ทั่วไปและคำหลัก Clojure:

  1. คำสำคัญใน Clojure ไม่ใช่สัญลักษณ์

    user> (symbol? :foo)  
    false
  2. คำหลักไม่ได้อยู่ในเนมสเปซใด ๆ เว้นแต่คุณจะมีคุณสมบัติเฉพาะ:

    user> (namespace :foo)
    nil
    user> (namespace ::foo)
    "user"

(ขอบคุณRainer Joswig ที่ให้ความคิดเกี่ยวกับสิ่งต่างๆแก่ฉัน)


10
สิ่งนี้อธิบายว่าความแตกต่างคืออะไร แต่ไม่ใช่เหตุผลที่ต้องใช้โครงสร้างที่แตกต่างกันสองแบบ Clojure ไม่สามารถสร้างบางสิ่งโดยใช้ความสามารถของทั้ง Keyword และ Symbol ได้หรือไม่?

25
คำหลักมีน้ำหนักเบาและมีไวยากรณ์ที่สะดวกฉันคิดว่านั่นคือทั้งหมดที่มีให้ ภาษาจะใช้งานได้ดีหากไม่มีพวกเขา แต่พวกเขาดีที่มีและมีการใช้กันอย่างแพร่หลาย คุณไม่สามารถมีความสามารถร่วมกันได้เนื่องจากคำหลักมักจะประเมินตนเอง (กล่าวคือคุณไม่สามารถใช้เป็นชื่อตัวแปรหรือฟังก์ชัน) และสัญลักษณ์โดยทั่วไปไม่สามารถประเมินตนเองได้เสมอไป
Brian Carper

1
ดูเหมือนว่าคำหลักที่มีประโยชน์มากขึ้นเป็นคีย์ใน hashmaps ฯลฯ ขณะที่พวกเขาไม่ได้เปลี่ยนการประเมินครั้งเดียว: VS(eval (eval ':a)) (eval (eval ''a))มีข้อดีอื่น ๆ อีกไหม? ประสิทธิภาพฉลาดเหมือนกันไหม?
kristianlm

5
(เหมือนกัน?: qwe: qwe) -> จริง (เหมือนกัน? 'qwe' qwe) -> เท็จ สัญลักษณ์ใช้สตริงภายในดังนั้นการเปรียบเทียบจึงรวดเร็วเช่นกัน
desudesudesu

29

Common Lispมีสัญลักษณ์คำหลัก

คำหลักเป็นสัญลักษณ์เช่นกัน

(symbolp ':foo) -> T

สิ่งที่ทำให้คำหลักพิเศษ:

  • : foo ถูกแยกวิเคราะห์โดย Common Lisp reader เป็นคีย์เวิร์ดสัญลักษณ์ :: foo
  • คีย์เวิร์ดประเมินตัวเอง:: foo ->: foo
  • แพคเกจหลักของสัญลักษณ์คำหลักคือแพ็คเกจ KEYWORD: คำหลัก: foo ->: foo
  • คำหลักจะถูกส่งออกจากแพ็คเกจ KEYWORD
  • คำหลักเป็นค่าคงที่ไม่อนุญาตให้กำหนดค่าอื่น

คำหลักอื่นเป็นสัญลักษณ์ธรรมดา ดังนั้นคำหลักสามารถตั้งชื่อฟังก์ชันหรือมีรายการคุณสมบัติได้

ข้อควรจำ: ในสัญลักษณ์ Common Lisp เป็นของแพ็คเกจ สามารถเขียนเป็น:

  • foo เมื่อสัญลักษณ์สามารถเข้าถึงได้ในแพ็คเกจปัจจุบัน
  • foo: bar เมื่อสัญลักษณ์ FOO ถูกส่งออกจากแพ็คเกจ BAR
  • foo :: bar เมื่อสัญลักษณ์ FOO อยู่ในแพ็คเกจ BAR

สำหรับสัญลักษณ์คำหลักที่หมายความว่า: foo, keyword: foo และ keyword :: foo เป็นสัญลักษณ์เดียวกันทั้งหมด ดังนั้นจึงมักไม่ใช้สัญกรณ์สองตัวหลัง

ดังนั้น: foo จะถูกแยกวิเคราะห์ให้อยู่ใน KEYWORD ของแพ็กเกจโดยสมมติว่าการไม่ระบุชื่อแพ็กเกจก่อนชื่อสัญลักษณ์หมายถึงโดยค่าเริ่มต้นแพ็กเกจ KEYWORD


6

คำหลักเป็นสัญลักษณ์ที่ประเมินตัวเองดังนั้นคุณจึงไม่จำเป็นต้องจำไว้ว่าต้องอ้าง


5
มันคืออะไร? การพิมพ์: แทนที่จะ 'ดูเหมือนจะไม่ใช่ชัยชนะที่ยิ่งใหญ่โดยเฉพาะอย่างยิ่งเนื่องจาก: เป็นการกดแป้นพิมพ์พิเศษบนแป้นพิมพ์ส่วนใหญ่
Laurence Gonsalves

11
มันเป็นมากกว่าแค่ตัวละครจริงๆ คำหลักยังคงเป็นคำหลักหลังจากการประเมินผลในขณะที่สัญลักษณ์จะถูกประเมินตามสิ่งที่พวกเขาผูก มันเหมือนกับความแตกต่างทางความหมายมากกว่าเพราะโดยทั่วไปแล้วจะใช้เพื่อวัตถุประสงค์ที่แตกต่างกัน
Greg Hewgill

13
คำหลักไม่ใช่สัญลักษณ์ใน Clojure
David Plumpton

4

: คำหลักยังได้รับการปฏิบัติเป็นพิเศษโดยคอลเลกชันจำนวนมากทำให้สามารถใช้ไวยากรณ์ที่สะดวกได้

(:user-id (get-users-map))

เหมือนกับ

((get-users-map) :user-id)

สิ่งนี้ทำให้สิ่งต่างๆยืดหยุ่นได้มากขึ้น


21
นอกจากนี้ยังเป็นจริงสำหรับสัญลักษณ์ ('a {' a 1 'b 2}) => 1 และ ({' a 1 'b 2}' b) => 2
Jonas

4

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

ทำไมคีย์เวิร์ดที่มีชื่อเหมือนกันจึงมีค่าแฮชเป็นของตัวเอง เนื่องจากการค้นหาในแผนที่และชุดต่างๆทำจากแฮชคีย์จึงช่วยเพิ่มประสิทธิภาพในการค้นหาในกรณีที่มีการค้นหาจำนวนมากไม่ใช่ในการค้นหา


0

คำหลักที่มีทั่วโลก , สัญลักษณ์ไม่ได้

ตัวอย่างนี้เขียนด้วย JavaScript แต่ฉันหวังว่ามันจะช่วยนำประเด็นนี้ไปได้

const foo = Symbol.for(":foo") // this will create a keyword
const foo2 = Symbol.for(":foo") // this will return the same keyword
const foo3 = Symbol(":foo") // this will create a new symbol
foo === foo2 // true
foo2 === foo3 // false

เมื่อคุณสร้างสัญลักษณ์โดยใช้Symbolฟังก์ชันคุณจะได้รับสัญลักษณ์ที่แตกต่าง / ส่วนตัวทุกครั้ง เมื่อคุณขอสัญลักษณ์ผ่านSymbol.forฟังก์ชันคุณจะได้รับสัญลักษณ์เดิมกลับมาทุกครั้ง

(println :foo) ; Clojure
System.out.println(RT.keyword(null, "foo")) // Java
console.log(System.for(":foo")) // JavaScript

เหล่านี้เหมือนกันทั้งหมด


ชื่ออาร์กิวเมนต์ของฟังก์ชันเป็นแบบโลคัล เช่นไม่ใช่คำหลัก

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.