Skip to content

Instantly share code, notes, and snippets.

@pnathan
Last active December 16, 2015 11:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pnathan/5428458 to your computer and use it in GitHub Desktop.
Save pnathan/5428458 to your computer and use it in GitHub Desktop.
clj-hash: clojure's hashes kind of brought to common lisp
(defmacro clj-hash (&rest kvs)
"Destructures `kvs`: assums keys and values are paired together:
kvs ::= k1 v1 ... kn vn
Defines a sequence of functions ki that will obtain the value of ki
from a hash table.
Raises simple-error on ki not being a keyword.
Example:
CL-USER> (:quux (clj-hash :foo t :bar t :quux :steele))
:STEELE
T
CL-USER>
This idea is ported from Clojure's hash accessors."
;; Todo: remove unneeded gensyms, as well as determing the correct
;; management of length
(let ((hash-table-sym (gensym))
(kv-macro (gensym))
(len (length kvs))
(param-sym (gensym))
;; may not need this
(len-sym (gensym)))
(loop for i from 0 below len by 2
do
(unless (eq (type-of (elt kvs i))
'keyword)
(error "~a not a keyword" (elt kvs i) ))
(when (fboundp (elt kvs i))
(warn "~a already defined... redefining" (elt kvs i) )))
(let ((function-list
(loop for i from 0 below len by 2
collect
`(defun ,(elt kvs i) (,param-sym)
(gethash ,(elt kvs i) ,param-sym)))))
`(let ((,hash-table-sym (make-hash-table))
;; quote kvs
(,kv-macro (list ,@kvs))
(,len-sym ,len))
(progn
,@function-list
(loop for i from 0 below ,len-sym by 2
do
(setf (gethash (elt ,kv-macro i) ,hash-table-sym)
(elt ,kv-macro (1+ i)))))
,hash-table-sym))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment