Tại sao Clojure lại có các từ khóa khác, ngoài ra còn có các biểu tượng khác?


130

Tôi có kiến ​​thức về các Lisps khác (đặc biệt là Scheme) từ khi trở về. Gần đây tôi đã đọc về Clojure . Tôi thấy rằng nó có cả "biểu tượng" và "từ khóa". Biểu tượng tôi quen thuộc, nhưng không phải với từ khóa.

Các Lisps khác có từ khóa không? Các từ khóa khác với các ký hiệu khác với ký hiệu khác nhau như thế nào (ví dụ: dấu hai chấm)?


Câu trả lời:


139

Đây là tài liệu Clojure cho Từ khóa và Biểu tượng.

Từ khóa là định danh tượng trưng để tự đánh giá. Họ cung cấp các bài kiểm tra công bằng rất nhanh ...

Biểu tượng là các định danh thường được sử dụng để chỉ một cái gì đó khác. Chúng có thể được sử dụng trong các hình thức chương trình để tham chiếu các tham số chức năng, cho phép các ràng buộc, tên lớp và vars toàn cầu ...

Các từ khóa thường được sử dụng như "các chuỗi không đổi" nhẹ, ví dụ như các khóa của bản đồ băm hoặc các giá trị công văn của đa phương thức. Các biểu tượng thường được sử dụng để đặt tên biến và hàm và nó ít phổ biến hơn để thao tác chúng dưới dạng đối tượng trực tiếp ngoại trừ trong macro và như vậy. Nhưng không có gì ngăn bạn sử dụng một biểu tượng ở mọi nơi bạn sử dụng từ khóa (nếu bạn không nhớ trích dẫn chúng mọi lúc).

Cách dễ nhất để thấy sự khác biệt là đọc Keyword.javaSymbol.javatrong nguồn Clojure. Có một vài sự khác biệt thực hiện rõ ràng. Ví dụ: Biểu tượng trong Clojure có thể có siêu dữ liệu và Từ khóa không thể.

Ngoài cú pháp dấu hai chấm đơn, bạn có thể sử dụng dấu hai chấm để tạo từ khóa đủ điều kiện không gian tên.

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

Lisp thông thường có từ khóa, cũng như Ruby và các ngôn ngữ khác. Họ hơi khác nhau trong các ngôn ngữ tất nhiên. Một số khác biệt giữa từ khóa Lisp thông thường và từ khóa Clojure:

  1. Từ khóa trong Clojure không phải là Biểu tượng.

    user> (symbol? :foo)  
    false
    
  2. Từ khóa không thuộc về bất kỳ không gian tên nào trừ khi bạn đủ điều kiện sử dụng chúng:

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

(Cảm ơn Rainer Joswig đã cho tôi ý tưởng về những thứ cần xem xét.)


10
Điều này giải thích những gì sự khác biệt là, nhưng không phải lý do tại sao hai cấu trúc khác nhau là cần thiết. Không thể Clojure đã tạo ra một cái gì đó với sự kết hợp các khả năng của cả Từ khóa và Biểu tượng?

25
Từ khóa rất nhẹ và có một cú pháp thuận tiện, tôi nghĩ đó là tất cả về nó. Ngôn ngữ sẽ hoạt động tốt nếu không có chúng nhưng chúng rất hay có và chúng được sử dụng rất rộng rãi. Bạn không thể có sự kết hợp các khả năng của họ vì Từ khóa luôn tự đánh giá (nghĩa là bạn không thể sử dụng chúng làm tên biến hoặc tên hàm) và các Biểu tượng nói chung không thể luôn tự đánh giá.
Brian Carper

1
Có vẻ như từ khóa là hữu ích hơn như phím trong hashmaps vv như họ không thay đổi một lần đánh giá: (eval (eval ':a))vs (eval (eval ''a)). Có những lợi thế khác? Hiệu suất khôn ngoan, chúng giống hệt nhau?
kristianlm

5
(giống hệt nhau ?: qwe: qwe) -> đúng. (giống hệt nhau? 'qwe' qwe) -> sai. Các biểu tượng sử dụng chuỗi nội bộ bên trong, do đó so sánh cũng nhanh.
desudesudesu

29

Lisp thông thường có các ký hiệu từ khóa.

Từ khóa là biểu tượng, quá.

(symbolp ':foo) -> T

Điều gì làm cho từ khóa trở nên đặc biệt:

  • : foo được trình đọc Lisp chung phân tích thành từ khóa ký hiệu :: foo
  • từ khóa tự đánh giá :: foo ->: foo
  • gói biểu tượng từ khóa là gói KEYWORD: keyword: foo ->: foo
  • từ khóa được xuất từ ​​gói KEYWORD
  • từ khóa là hằng số, nó không được phép gán một giá trị khác

Nếu không các từ khóa là biểu tượng thông thường. Vì vậy, từ khóa có thể đặt tên chức năng hoặc có danh sách tài sản.

Hãy nhớ rằng: trong các ký hiệu Lisp thông thường thuộc về một gói. Điều này có thể được viết là:

  • foo, khi biểu tượng có thể truy cập trong gói hiện tại
  • foo: bar, khi ký hiệu FOO được xuất từ ​​gói BAR
  • foo :: bar, khi ký hiệu FOO nằm trong gói BAR

Đối với các ký hiệu từ khóa có nghĩa là: foo, keyword: foo và keyword :: foo đều là cùng một ký hiệu. Do đó, hai ký hiệu sau thường không được sử dụng.

Vì vậy: foo chỉ được phân tích cú pháp để nằm trong gói KEYWORD, giả sử rằng không đưa ra tên gói trước tên biểu tượng có nghĩa là mặc định gói KEYWORD.


6

Từ khóa là biểu tượng tự đánh giá, vì vậy bạn không cần phải trích dẫn chúng.


5
Là nó? Gõ: thay vì 'dường như không phải là một chiến thắng lớn, đặc biệt là: là một phím nhấn phụ trên hầu hết các bàn phím.
Laurence Gonsalves

11
Chà, thực sự không chỉ là nhân vật. Từ khóa ở lại từ khóa sau khi đánh giá, trong khi các biểu tượng được ước tính cho bất cứ điều gì chúng liên kết. Nó giống như một sự khác biệt về ngữ nghĩa, bởi vì chúng thường được sử dụng cho các mục đích khác nhau.
Greg Hewgill

13
Từ khóa không phải là biểu tượng trong Clojure
David Plumpton

4

: từ khóa cũng được xử lý đặc biệt bởi nhiều bộ sưu tập, cho phép một số cú pháp thực sự thuận tiện.

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

giống như

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

điều này làm cho mọi thứ linh hoạt hơn một chút


21
Điều này cũng đúng với các ký hiệu, ('a {' a 1 'b 2}) => 1 và ({' a 1 'b 2}' b) => 2.
Jonas

4

Đối với từ khóa, giá trị băm được tính toán và lưu vào bộ đệm khi từ khóa được xây dựng lần đầu tiên. Khi tra từ khóa dưới dạng khóa băm, nó chỉ đơn giản trả về giá trị băm được tính toán trước. Đối với chuỗi và ký hiệu, hàm băm được tính toán lại trên mỗi lần tra cứu.

Tại sao các từ khóa được đặt tên giống nhau luôn giống hệt nhau, chúng chứa các giá trị băm của riêng chúng. Vì tìm kiếm trong bản đồ và bộ được tạo từ các khóa băm, điều này cho thấy hiệu quả tìm kiếm tốt hơn trong trường hợp có nhiều tìm kiếm, không phải trong chính tìm kiếm.


0

Từ khóa là toàn cầu , biểu tượng thì không .

Ví dụ này được viết bằng JavaScript, nhưng tôi hy vọng nó sẽ giúp đưa ra quan điểm.

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

Khi bạn xây dựng một biểu tượng bằng cách sử dụng Symbolchức năng, bạn sẽ nhận được một biểu tượng riêng biệt / riêng tư mỗi lần. Khi bạn yêu cầu một biểu tượng thông qua Symbol.forchức năng, bạn sẽ nhận lại cùng một biểu tượng mỗi lần.

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

Tất cả đều giống nhau.


Tên đối số chức năng là cục bộ. tức là không từ khóa.

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.