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)
(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)

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

常规方法是用关键词(而不是符号)作为属性值,但没有什么阻止你使用符号。

...