From: Damien Cassou
Subject: A macro to print function arguments
Date: 
Message-ID: <1167921102.944572.159780@v33g2000cwv.googlegroups.com>
Hi,

I'm learning macros and, as an exercise, I decided to write a macro
that will help me writing functions which print their arguments.
Example:

(defunprint mySum (a b)
  (+ a b))

> (mySum 2 99)
mySum(a=2 b=99)
101

I nearly managed to do it:

(defmacro defunprint (name args &body body)
  `(defun ,name ,args
     (format t ,(format nil "~A~A"
			name
			(mapcar (lambda (arg)
				  (format nil "~A=~~A" (string-downcase arg)))
				args))
	     ,@args)

     ,@body))

> (macroexpand-1 '(defunprint mySum (a b) (+ a b)))
(DEFUN MYSUM (A B) (FORMAT T "MYSUM(a=~A b=~A)" A B) (+ A B))

I have two problems:

- how can I get the function name case right ? I would like to print
"mySum" instead of MYSUM.
- how can I manage &rest, &key... ?


Thank you very much

-- 
Damien Cassou

From: Geoff Wozniak
Subject: Re: A macro to print function arguments
Date: 
Message-ID: <1167925937.866032.214650@q40g2000cwq.googlegroups.com>
On Jan 4, 9:31 am, "Damien Cassou" <·············@gmail.com> wrote:
> I have two problems:
>
> - how can I get the function name case right ? I would like to print
> "mySum" instead of MYSUM.

Most of the time, Lisp systems ignore case.  So internally, the system
sees "mySum" as "MYSUM".  You have to get it to read the code (in the
sense of the function READ) by altering the readtable.

    (setf (readtable-case *readtable*) :preserve)

That's a simple way to get it to work, but it can cause problems if
you're not careful.  Ultimately, I wouldn't put too much concern into
handing case sensitivity, but hey, I'm not you. :)

> - how can I manage &rest, &key... ?
>

Depends on what you want to do with them.  It's probably simplest to
just remove them from the argument list by examining the constant
LAMBDA-LIST-KEYWORDS.  However, then you're left with the issue of
arguments that have been given default values, in which case the name
of the argument is usually the first element of the list that
constitutes the argument.  To be completely accurate, however, you're
going to have to parse the lambda list (a.k.a. arguments) to deal with
all the possible cases.

Parsing lambda lists can be a real pain, but if you are only interested
in the common cases (and ignore &AUX "arguments"), just remove the
lambda list keywords and grab the first element of any argument that
happens to be a list.  Parsing the lambda list is left as an exercise
if you want to go that far.

    (defun simple-filter-lambda-list (lambda-list)
      (mapcar #'(lambda (arg) (if (listp arg) (first arg) arg))
                   (remove-if #'(lambda (e) (member e
lambda-list-keywords)) lambda-list)))

-- 
Geoff
From: Damien Cassou
Subject: Re: A macro to print function arguments
Date: 
Message-ID: <1168286825.947093.104270@v33g2000cwv.googlegroups.com>
Thank you very much to both of you.


-- 
Damien Cassou
From: Pascal Bourguignon
Subject: Re: A macro to print function arguments
Date: 
Message-ID: <877iw2dcez.fsf@thalassa.informatimago.com>
"Damien Cassou" <·············@gmail.com> writes:

> Hi,
>
> I'm learning macros and, as an exercise, I decided to write a macro
> that will help me writing functions which print their arguments.
> Example:
>
> (defunprint mySum (a b)
>   (+ a b))
>
>> (mySum 2 99)
> mySum(a=2 b=99)
> 101
>
> I nearly managed to do it:
>
> (defmacro defunprint (name args &body body)
>   `(defun ,name ,args
>      (format t ,(format nil "~A~A"
> 			name
> 			(mapcar (lambda (arg)
> 				  (format nil "~A=~~A" (string-downcase arg)))
> 				args))
> 	     ,@args)
>
>      ,@body))
>
>> (macroexpand-1 '(defunprint mySum (a b) (+ a b)))
> (DEFUN MYSUM (A B) (FORMAT T "MYSUM(a=~A b=~A)" A B) (+ A B))
>
> I have two problems:
>
> - how can I get the function name case right ? I would like to print
> "mySum" instead of MYSUM.

(SETF (READTABLE-CASE *READTABLE*) :PRESERVE)

From now on, mind using the right case, that is, uppercase for all the
symbols from CL (and most other implementation specific packages).

An alternative, is to use :INVERT, which may be more practical.


C/USER[734]> (let ((*readtable* (copy-readtable nil))) 
               (setf (readtable-case *readtable*) :invert)
               (read-from-string "(abc ABC aBc)"))
(ABC |abc| |aBc|) ;
13
C/USER[735]> (let ((*readtable* (copy-readtable nil))) 
               (setf (readtable-case *readtable*) :preserve)
               (read-from-string "(abc ABC aBc)"))
(|abc| ABC |aBc|) ;
13


But the real answer is that the real name of the symbol mySum is
really "MYSUM", nothing else.  Why don't you type MY-SUM instead?


> - how can I manage &rest, &key... ?

You'd have to parse the lambda list.
Have a look at: http://darcs.informatimago.com/lisp/common-lisp/source.lisp


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.