Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Namespaces and vars by

I'm taxed with porting a mess of old Lisp code into the 21st century.
I came across Clojure and think maybe it might be the avenue of best approach.
I am an absolute newbie to Clojure.

The Lisp code makes extensive use of symbol property lists.
Do Clojure symbols have property lists? Or something that "works" as a property list?

In Lisp, I could say:

(put 'fly 'verb 'transitive) ; The Verb property of "fly" is "transitive".
--> 'transitive
(put 'fly 'noun '(a buzzing little bug)) ; The Noun property of "fly" is "a buzzing little bug"
--> (a buzzing little bug)
(get 'fly 'verb) ; Show me the Verb property of "fly"
--> transitive
(symbol-plist 'fly) ; Show me all the properties of "fly"
--> (verb transitive noun (a buzzing little bug))

Does Clojure support symbol property-lists?

2 Answers

+2 votes

Clojure allow you to attach metadata (map of arbitrary info) to symbols and other objects (collections, vars, etc), which is probably a similar facility. In Clojure metadata, you could attach the verb and noun as metadata to a symbol (using keywords as keys is more idiomatic but anything is ok). I think the major difference is you'll have immutable vals/metadata instead of mutable.

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

Also see:


+1 vote

Well, yes. The data structure of property list is essentially a nested map (at least from what I can deduce from your example, i'm not really familiar with the original property lists). Hash-maps are built in i Clojure and very easy to work with. They can take any value as a key and value.

What differs more is that the example you give is mutable. This is certainly doable using atoms, outlined below, but a major thing with Clojure
is that it is syntactically cluncky to do things mutable. However, here's something working as you outlined:

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

Another thing is that people often use :keywords rather than 'symbols because symbols tend to try to resolve in annoying ways if not quoted. The same thing goes with lists. In litteral data-structures, it is more common to have collections as vectors (or sets).

And the data you construct in you example could be represented with

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

This data structure is immutable. symbol-plist is equal to (keys (get the-structure 'fly)), get is (get (get ... 'fly) 'verb) or (get-in ... ['fly 'verb]).

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

But you have to save the reference, either in a closure during the execution, like

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

or in an atom as outlined in the first code block.

The idiomatic way is to use keywords (not symbols) for property values, but nothing prevents you from using symbols.