I'm trying to write a simple triplestore in Common Lisp that will store triples in the form subject-predicate-object. The code is inspired by the book "Programming the Semantic Web".
(defvar triplestore-graph (make-hash-table))
(defun triplestore-init ()
(puthash :spo (make-hash-table) triplestore-graph)
(puthash :pos (make-hash-table) triplestore-graph)
(puthash :osp (make-hash-table) triplestore-graph))
(defun triplestore-add (s p o)
(triplestore-add-to-index :spo s p o)
(triplestore-add-to-index :pos p o s)
(triplestore-add-to-index :osp o s p))
(defun triplestore-add-to-index (index a b c)
(let ((index (gethash index triplestore-graph)))
(cond ((not (gethash a index))
(let ((tmp (make-hash-table)))
(puthash a
(progn
(puthash b
(list c)
tmp)
tmp)
index)))
((not (gethash b (gethash a index)))
(puthash b
(list c)
(gethash a index)))
(t
(nconc (list c)
(gethash b
(gethash a index)))))))
Here (puthash k v table)
is defined as (setf (gethash k table) v)
. The code above is roughly equivalent to the Python code:
graph = {}
def init(graph):
graph['_spo'] = {}
graph['_pos'] = {}
graph['_osp'] = {}
def add(graph, (s, p, o)):
_addToIndex(graph['_spo'], s, p, o)
_addToIndex(graph['_pos'], p, o, s)
_addToIndex(graph['_osp'], o, s, p)
def _addToIndex(index, a, b, c):
if a not in index:
index[a] = {b: set([c])}
elif b not in index[a]:
index[a][b] = set([c])
else:
index[a][b].add(c)
How can i improve readability and elegantness of the Common Lisp code? I'm mainly concerned that operations with hash-tables are verbose comparing to Python's equivalents. Are there macros for hash-table handling, for example?