From: Yoel Jacobsen
Subject: Beginner question: help with macros
Date: 
Message-ID: <d1m312$6k5$1@news2.netvision.net.il>
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

From: ···············@yahoo.com
Subject: Re: Beginner question: help with macros
Date: 
Message-ID: <1111416689.288215.246150@z14g2000cwz.googlegroups.com>
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."))))
From: Peder O. Klingenberg
Subject: Re: Beginner question: help with macros
Date: 
Message-ID: <ksvf7ltkdc.fsf@beto.netfonds.no>
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.
From: Alan Crowe
Subject: Re: Beginner question: help with macros
Date: 
Message-ID: <86r7i8u1hi.fsf@cawtech.freeserve.co.uk>
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