I would like to define a macro named defhash that will work as follows:
(defhash myhash) will create <somehash> and will define the myhash macro.
(myhash "x") will be translated to (gethash "x" <somehash>)
(myhash "x" 5) will be translated to (setf (gethash "x" <somehash>) 5)
The problem: since macros are evaluated at compile-time, I cannot test
for the second argument of the created hash. I can define myhash as a
function which will test for this argument at run-time but then (myhash
"x") will not be setf-able.
How can it be implemented?
Yoel
You can test for the number of arguments at compile-time.
(defmacro myhash (&rest args)
(case (length args)
(1
;; case of (myhash key). Note how
;; the comma is outside (first args).
`(gethash ,(first args) something-more))
(2
;; case of (myhash key new-value)
`(setf (gethash ,(first args) something-more) something-else))
(t
;; next error happens at compile time,
;; so the programmer can fix it
(error "Wrong number of args to myhash."))))
Yoel Jacobsen <····@emet.co.il> writes:
> I would like to define a macro named defhash that will work as follows:
>
> (defhash myhash) will create <somehash> and will define the myhash macro.
> (myhash "x") will be translated to (gethash "x" <somehash>)
> (myhash "x" 5) will be translated to (setf (gethash "x" <somehash>) 5)
myhash should be a function, not a macro. There is nothing in your
stated requirements that justifies it being a macro.
> I can define myhash as a function which will test for this argument
> at run-time but then (myhash "x") will not be setf-able.
So you want (setf (myhash "x") 5) to work the same as (myhash "x" 5) ?
Define a setf function for it.
> How can it be implemented?
Completely untested stab at it:
(defmacro defhash (name &rest make-hash-args)
(let ((hash-name (gensym)))
`(let ((,hash-name (make-hash-table ,@make-hash-args)))
(defun ,name (key &optional (newval nil setval-p))
(if setval-p
(setf (gethash key ,hash-name) newval)
(gethash key ,hash-name)))
(defun (setf ,name) (newval key)
(setf (gethash key ,hash-name) newval))
,hash-name)))
...Peder...
--
I wish a new life awaited _me_ in some off-world colony.
Yoel Jacobsen wrote:
> I would like to define a macro named defhash that ...
paraphrasing
> ... does something else if an optional argument is present.
supplied-p arguments are very shiny and attractive and are
available for both macros and functions (and on keyword
arguments)
(defmacro do-two-things(first &optional (second nil both-supplied))
(if both-supplied
`(progn ,first ,second)
;; Do something that cannot be done with a default
;; value for the second argument
`(progn ,first ,first ,first) ))
* (macroexpand-1 '(do-two-things (print 'foo)(print 'bar)))
=> (PROGN (PRINT 'FOO) (PRINT 'BAR))
* (macroexpand-1 '(do-two-things (print 'foo)))
=> (PROGN (PRINT 'FOO) (PRINT 'FOO) (PRINT 'FOO))
* (defun add (x &optional (y 0 two-arguments))
(if two-arguments
(+ x y)
(error "I changed my mind about making the second argument optional.")))
* (add 5 7) => 12
* (add 4)
Error in function ADD:
I changed my mind about making the second argument optional.
Alan Crowe
Edinburgh
Scotland