为什么Clojure除了“符号”之外还有“关键字”?

时间:2009-10-06 19:20:36

标签: lisp clojure scheme keyword

我从其他方面了解其他Lisps(特别是Scheme)。最近我一直在阅读Clojure。我看到它有“符号”和“关键字”。我熟悉的符号,但没有关键字。

其他Lisps有关键字吗?关键字如何与除了具有不同符号之外的符号(即:冒号)不同?

6 个答案:

答案 0 :(得分:131)

以下是关键字和符号的Clojure documentation

  

关键字是评估自己的符号标识符。它们提供了非常快速的平等测试...

     

符号是通常用于指代其他内容的标识符。它们可以在程序表单中用于引用函数参数,绑定,类名和全局变量......

关键字通常用作轻量级“常量字符串”,例如对于哈希映射的键或多方法的分派值。符号通常用于命名变量和函数,除了在宏等中之外,将它们直接作为对象进行操作的情况较少见。但是没有什么可以阻止你在使用关键字的地方使用符号(如果你不介意一直引用它们的话)。

查看差异的最简单方法是阅读Clojure源代码中的Keyword.javaSymbol.java。有一些明显的实现差异。例如,Clojure中的符号可以包含元数据,而关键字则不能。

除了单冒号语法之外,您还可以使用双冒号来创建名称空间限定的关键字。

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

Common Lisp具有关键字,Ruby和其他语言也是如此。当然,它们在这些语言上略有不同。 Common Lisp关键字和Clojure关键字之间存在一些差异:

  1. Clojure中的关键字不是符号。

    user> (symbol? :foo)  
    false
    
  2. 除非您特别限定关键字,否则关键字不属于任何命名空间:

    user> (namespace :foo)
    nil
    user> (namespace ::foo)
    "user"
    
  3. (感谢Rainer Joswig给了我关于要看的事情的想法。)

答案 1 :(得分:30)

Common Lisp 有关键字符号。

关键字也是符号。

(symbolp ':foo) -> T

什么使关键字变得特别:

  • :Common Lisp reader将foo解析为符号关键字:: foo
  • 关键字评估自己:: foo - > :FOO
  • 关键字符号的主包是KEYWORD包:keyword:foo - > :FOO
  • 关键字从包KEYWORD
  • 导出
  • 关键字是常量,不允许分配不同的值

否则关键字是普通符号。因此,关键字可以命名函数或具有属性列表。

记住:在Common Lisp中,符号属于一个包。这可以写成:

  • foo,当符号可在当前包中访问时
  • foo:bar,当从包BAR导出符号FOO时
  • foo :: bar,当符号FOO在包BAR中时

对于关键字符号,表示:foo,keyword:foo和keyword :: foo都是相同的符号。因此通常不使用后两种符号。

所以:foo被解析为在KEYWORD包中,假设在符号名称之前没有给出包名,默认情况下是KEYWORD包。

答案 2 :(得分:5)

关键字是评估自己的符号,因此您不必记住引用它们。

答案 3 :(得分:4)

:许多集合也特别对待关键字,允许一些非常方便的语法。

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

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

这使事情变得更加灵活

答案 4 :(得分:4)

对于关键字,当关键字为时,会计算并缓存哈希值 首先构建。查找关键字作为哈希键时,它就是简单的 返回预先计算的散列值。对于字符串和符号,哈希是 每次查询都会重新计算。

为什么相同的命名关键字始终相同,它们包含自己的哈希值。 由于地图和集合中的搜索是通过散列键进行的,因此在大量搜索的情况下,搜索效率会提高,而不是搜索本身。

答案 5 :(得分: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)