请在 2024 Clojure 发展状况调查 中分享您的想法!

欢迎!有关此功能的信息,请参阅关于页面。

+1 表扬
命名空间和变量

我正在尝试将一堆旧的 Lisp 代码移植到21世纪。
我发现了 Clojure,认为这可能是一条最好的途径。
我是 Clojure 的绝对新手。

Lisp 代码广泛使用了符号属性列表。
Clojure 符号有属性列表吗?或者有像属性列表一样“工作”的东西?

在 Lisp 中,我可以说

(put 'fly 'verb 'transitive) ; "fly" 的动词属性是 "transitive"。
--> 'transitive
(put 'fly 'noun '(a buzzing little bug)) ; "fly" 的名词属性是 "a buzzing little bug"
--> (a buzzing little bug)
(get 'fly 'verb) ; 显示 "fly" 的动词属性
--> transitive
(symbol-plist 'fly) ; 显示 "fly" 的所有属性
--> (verb transitive noun (a buzzing little bug))

Clojure 支持符号属性列表吗?

2 答案

+2 表扬

Clojure 允许您将元数据(任意信息的映射)附加到符号和其他对象(集合、变量等),这可能与类似的设施相似。在 Clojure 元数据中,您可以将动词和名词作为元数据附加到符号(使用关键字作为键更符合习惯,但任何内容均可)。我认为主要的区别是您将拥有不可变的值/元数据而不是可变。

(def f (with-meta 'fly {'verb 'transitive, 'noun '(a buzzing little bug)}))
(get (meta f) 'verb)
;;=> transitive
(meta f)
;;=> {verb transitive noun (a buzzing little bug)}

另请参阅

https://clojure.org/reference/metadata

+1 表扬

嗯,是的。属性列表的数据结构本质上是一个嵌套映射(至少从我分析你的示例来看是如此,我对原始属性列表不是特别熟悉)。哈希表在Clojure中内置,并且非常容易使用。它可以接受任何值作为键和值。

更不同的是,你给出的示例是可变的。当然可以使用下文概述的atom来实现,但Clojure一个重要的事情是进行可变操作在语法上相对繁琐。
然而,以下是如何按你概述的方式来实现

(def db (atom {}))

(defn put [word prop value]
  (swap db assoc-in [word prop] value))

(defn get' [word prop]
  (get-in @db [word prop]))

(defn symbol-plist [word]
  (keys (get-in @db [word])))

还有一点是,人们常常使用`:keywords`而不是`'symbols`,因为如果不加引号,符号往往会以一种令人讨厌的方式尝试解析。同样,这也适用于列表。在文学数据结构中,将集合作为向量(或集合)更常见。

你构造的数据可以使用以下方式表示

{'fly {'noun '(a buzzing little bug)
       'verb 'transitive}}
  

这种数据结构是不可变的。symbol-plist等于(keys (get the-structure 'fly)),get是(get (get ... 'fly) 'verb)(get-in ... ['fly 'verb])

Put是(assoc-in ... ['fly 'adjective] 'nah-not-really)

但你必须保存引用,无论是在执行期间的一个闭包中,如

(let [db {'fly {'noun '(a buzzing little bug) 'verb 'transitive}}
      db (assoc-in db ['cat 'noun] '(a little furry animal))
      ...]
    db)

或者在第一个代码块中概述的atom中。

习惯用法是使用关键字(而不是符号)作为属性值,但这并不能阻止你使用符号。

...