From: Peter Szabo
Subject: Q: to a simple macro
Date: 
Message-ID: <40D4734B.3040202@debitel.net>
Hi,

Why is the function g undifiend? Or how to "insert" info
befor and after running a function (e.g. for debugging)?
Thanks  in advance!

(defmacro mydefun (name arg-list &body body)
  `(let* ((g (defun ,name ,arg-list ,@body))
            (f  (defun ,name ,arg-list
                   (let ((res nil))
                      (print "in")
                      (setf res (g ,@arg-list))
                     (print "out")
                   res))))
       f))
------------------------------------------------------
I'm using Lispworks Personal:

CL-USER 3 > (compile 'mydefun)
MYDEFUN
NIL
NIL

CL-USER 4 > (mydefun foo (x) (+ x 1))
FOO

CL-USER 5 > (foo 1)

"in"
Error: Undefined function G called with arguments (1).
          1 (continue) Try invoking G again.
          ........  etc.
---------------------------------------------------------

From: James P. Massar
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <n4u8d0t6eopjm1s4iepu2vkvp45v6bnv57@4ax.com>
On Sat, 19 Jun 2004 19:09:31 +0200, Peter Szabo <······@debitel.net>
wrote:

>Hi,
>
>Why is the function g undifiend? Or how to "insert" info
>befor and after running a function (e.g. for debugging)?
>Thanks  in advance!
>
>(defmacro mydefun (name arg-list &body body)
>  `(let* ((g (defun ,name ,arg-list ,@body))
>            (f  (defun ,name ,arg-list
>                   (let ((res nil))
>                      (print "in")
>                      (setf res (g ,@arg-list))
>                     (print "out")
>                   res))))
>       f))

You're defining a function by the name of 'name' twice.
 
This will do something along the lines of what you think you want:

(defmacro mydefun (name arg-list &body body)
              `(let* ((g (lambda (,@arg-list) ,@body))
                          (f  (defun ,name ,arg-list
                                  (let ((res nil))
                                    (print "in")
                                     (setf res (funcall g ,@arg-list))
                                     (print "out")
                                      res))))
                           f))  

But why not something simpler like:

(defmacro mydefun (name arg-list &body body)
  `(defun ,name (,@arg-list) 
      (prog2 (print "in") (progn ,@body) (print   "out"))))

Or better yet, take a look at the documentation for TRACE and UNTRACE
 

>------------------------------------------------------
>I'm using Lispworks Personal:
>
>CL-USER 3 > (compile 'mydefun)
>MYDEFUN
>NIL
>NIL
>
>CL-USER 4 > (mydefun foo (x) (+ x 1))
>FOO
>
>CL-USER 5 > (foo 1)
>
>"in"
>Error: Undefined function G called with arguments (1).
>          1 (continue) Try invoking G again.
>          ........  etc.
>---------------------------------------------------------
From: Kalle Olavi Niemitalo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <87d63ufyhm.fsf@Astalo.kon.iki.fi>
James P. Massar <······@alum.mit.edu> writes:

> But why not something simpler like:
>
> (defmacro mydefun (name arg-list &body body)
>   `(defun ,name (,@arg-list) 
>       (prog2 (print "in") (progn ,@body) (print   "out"))))

That would not allow declarations at the beginning of the body.
(Also, it cannot return multiple values, but neither could the
original.)

> Or better yet, take a look at the documentation for TRACE and UNTRACE

And *TRACE-OUTPUT*, if you're printing the traces yourself.
From: James P. Massar
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <1cabd018pb1c6p3g9fs853ksvhlqe8qa87@4ax.com>
On Sun, 20 Jun 2004 11:02:45 +0300, Kalle Olavi Niemitalo <···@iki.fi>
wrote:

>James P. Massar <······@alum.mit.edu> writes:
>
>> But why not something simpler like:
>>
>> (defmacro mydefun (name arg-list &body body)
>>   `(defun ,name (,@arg-list) 
>>       (prog2 (print "in") (progn ,@body) (print   "out"))))
>
>That would not allow declarations at the beginning of the body.
>(Also, it cannot return multiple values, but neither could the
>original.)
>
 
True.  It was just illustrative.  My take was the person asking the
question needed help at a much more basic level than worrying
about those issues.
From: Peter Szabo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <40D7402A.9070808@debitel.net>
TRACE is ok. But my intent was to construct a macro that "inserts" 
additional code
(e.g. calling another function) at the beginning and at the end of the 
body of a defun.
That is, using mydefun instead of defun should behave identically.
The inserted code informs than a "test manager", which collects 
(certain) information
about the behaviour of the function created by mydefun.  Is this possible?
Thanks for all the helps.
peter
-------------------------------------------------------------------------------------
Kalle Olavi Niemitalo wrote:

>James P. Massar <······@alum.mit.edu> writes:
>
>  
>
>>But why not something simpler like:
>>
>>(defmacro mydefun (name arg-list &body body)
>>  `(defun ,name (,@arg-list) 
>>      (prog2 (print "in") (progn ,@body) (print   "out"))))
>>    
>>
>
>That would not allow declarations at the beginning of the body.
>(Also, it cannot return multiple values, but neither could the
>original.)
>
>  
>
>>Or better yet, take a look at the documentation for TRACE and UNTRACE
>>    
>>
>
>And *TRACE-OUTPUT*, if you're printing the traces yourself.
>  
>
From: Peter Seibel
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <m34qp44m1p.fsf@javamonkey.com>
Peter Szabo <······@debitel.net> writes:

> TRACE is ok. But my intent was to construct a macro that "inserts"
> additional code (e.g. calling another function) at the beginning and
> at the end of the body of a defun. That is, using mydefun instead of
> defun should behave identically. The inserted code informs than a
> "test manager", which collects (certain) information about the
> behaviour of the function created by mydefun. Is this possible?
> Thanks for all the helps.

Yes, the example you quoted does that. Kalle was just picking nits
which might or might not matter to you. In particular if you wrote:

  (mydefun foo (x y)
    (declare (number x y))
    (stuff-with x y))

the declaration would be lost when it got translated to:

  (defun foo (x y)
    (prog2
      (print "in")
      (progn
        (declare (number x y))
        (stuff-with x y))
      (print "out")))

Similar bad things would happen if you used doc strings. Depending how
you are actally going to use MYDEFUN these defficiencies might or
might not matter. (If you really cared, you could grovel through the
body argument to mydefun and pull out docstrings and declarations and
put them in the right place in the expansion.)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: JP Massar
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <0mred01r3pso81ncr6ufaec6lej7kkbli6@4ax.com>
On Mon, 21 Jun 2004 21:52:39 GMT, Peter Seibel <·····@javamonkey.com>
wrote:
 
>
>Similar bad things would happen if you used doc strings. Depending how
>you are actally going to use MYDEFUN these defficiencies might or
>might not matter. (If you really cared, you could grovel through the
>body argument to mydefun and pull out docstrings and declarations and
>put them in the right place in the expansion.)
>
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Returns four values
;; 1.  Doc string or NIL
;; 2.  List of decls (or NIL)
;; 3.  List of body forms (Not including bad decls from 4 below)
;; 4.  Declaration forms which are not in legal position

(defun parse-doc-decls-body (forms)
  (let ((doc-string nil)
        (declarations nil))
    (flet ((decl-form? (x) (and (consp x) (eq (car x) 'declare))))
      ;; look for declarations and doc string
      (do* ((f forms (cdr f)))
           ((null f) (setq forms f))
        (if (and (typep (car f) 'string) (null doc-string) (cdr f))
            (setq doc-string (car f))
          (if (decl-form? (car f))
              (push (car f) declarations)
            (progn (setq forms f) (return)))))
      (values
       doc-string
       declarations
       (remove-if #'decl-form? forms)
       (remove-if-not #'decl-form? forms)
       ))))
From: Peter Szabo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <40D86D64.5050008@debitel.net>
If there is no simple solution, this could be a help.
Thank you very much!
peter

JP Massar wrote:

>On Mon, 21 Jun 2004 21:52:39 GMT, Peter Seibel <·····@javamonkey.com>
>wrote:
> 
>  
>
>>Similar bad things would happen if you used doc strings. Depending how
>>you are actally going to use MYDEFUN these defficiencies might or
>>might not matter. (If you really cared, you could grovel through the
>>body argument to mydefun and pull out docstrings and declarations and
>>put them in the right place in the expansion.)
>>
>>    
>>
> 
>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>
>;; Returns four values
>;; 1.  Doc string or NIL
>;; 2.  List of decls (or NIL)
>;; 3.  List of body forms (Not including bad decls from 4 below)
>;; 4.  Declaration forms which are not in legal position
>
>(defun parse-doc-decls-body (forms)
>  (let ((doc-string nil)
>        (declarations nil))
>    (flet ((decl-form? (x) (and (consp x) (eq (car x) 'declare))))
>      ;; look for declarations and doc string
>      (do* ((f forms (cdr f)))
>           ((null f) (setq forms f))
>        (if (and (typep (car f) 'string) (null doc-string) (cdr f))
>            (setq doc-string (car f))
>          (if (decl-form? (car f))
>              (push (car f) declarations)
>            (progn (setq forms f) (return)))))
>      (values
>       doc-string
>       declarations
>       (remove-if #'decl-form? forms)
>       (remove-if-not #'decl-form? forms)
>       ))))
>
>  
>
From: Peter Szabo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <40D86CE3.7080206@debitel.net>
Kalles construct is the shortest (so the most elegant) with the problem of
declarations and documentation strings. But if I use the hints of James
and do a little modification:

(defun entry-func ()
  (print "in"))

(defun exit-func ()
  (print "out"))


(defmacro mydefun (name arg-list &body body)
  "modifies body by first calling entry-foo, than saves what
   body yields. Finally exit-foo is called and the saved result is returned"
  (declare (inline g))
  `(let* ((g (lambda (,@arg-list) ,@body))
      (f (defun ,name ,arg-list
           (progn
         (entry-func)
         (multiple-value-prog1 (funcall g ,@arg-list)
                       (exit-func))))))
     f))

than the lambda expression bound to g holds the original body with 
declarations and docs.
So nothing is lost and multiple-value-prog1 now returns multiple values. 
Is this correct?
Or am I overlooking something?
---------------------------------------------------------------
Peter Seibel wrote:

>Peter Szabo <······@debitel.net> writes:
>
>  
>
>>TRACE is ok. But my intent was to construct a macro that "inserts"
>>additional code (e.g. calling another function) at the beginning and
>>at the end of the body of a defun. That is, using mydefun instead of
>>defun should behave identically. The inserted code informs than a
>>"test manager", which collects (certain) information about the
>>behaviour of the function created by mydefun. Is this possible?
>>Thanks for all the helps.
>>    
>>
>
>Yes, the example you quoted does that. Kalle was just picking nits
>which might or might not matter to you. In particular if you wrote:
>
>  (mydefun foo (x y)
>    (declare (number x y))
>    (stuff-with x y))
>
>the declaration would be lost when it got translated to:
>
>  (defun foo (x y)
>    (prog2
>      (print "in")
>      (progn
>        (declare (number x y))
>        (stuff-with x y))
>      (print "out")))
>
>Similar bad things would happen if you used doc strings. Depending how
>you are actally going to use MYDEFUN these defficiencies might or
>might not matter. (If you really cared, you could grovel through the
>body argument to mydefun and pull out docstrings and declarations and
>put them in the right place in the expansion.)
>
>-Peter
>
>  
>
From: Kalle Olavi Niemitalo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <87y8mfqtgb.fsf@Astalo.kon.iki.fi>
Peter Szabo <······@debitel.net> writes:

> Kalles construct is the shortest (so the most elegant) with the problem of
> declarations and documentation strings.

You must be referring to someone else.  I didn't construct any
Lisp code in this thread.
From: Peter Szabo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <40D88E17.3010203@debitel.net>
Oh! Yes, sorry for the confusion. This was James P. Massar.


Kalle Olavi Niemitalo wrote:

>Peter Szabo <······@debitel.net> writes:
>
>  
>
>>Kalles construct is the shortest (so the most elegant) with the problem of
>>declarations and documentation strings.
>>    
>>
>
>You must be referring to someone else.  I didn't construct any
>Lisp code in this thread.
>  
>
From: Tim Bradshaw
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <fbc0f5d1.0406230356.f931bab@posting.google.com>
Peter Szabo <······@debitel.net> wrote in message news:<················@debitel.net>...
> Kalles construct is the shortest (so the most elegant) with the problem of
> declarations and documentation strings. But if I use the hints of James
> and do a little modification:
> 
> (defun entry-func ()
>   (print "in"))
> 
> (defun exit-func ()
>   (print "out"))
> 
> 
> (defmacro mydefun (name arg-list &body body)
>   "modifies body by first calling entry-foo, than saves what
>    body yields. Finally exit-foo is called and the saved result is returned"
>   (declare (inline g))
>   `(let* ((g (lambda (,@arg-list) ,@body))
>       (f (defun ,name ,arg-list
>            (progn
>          (entry-func)
>          (multiple-value-prog1 (funcall g ,@arg-list)
>                        (exit-func))))))
>      f))
> 
> than the lambda expression bound to g holds the original body with 
> declarations and docs.
> So nothing is lost and multiple-value-prog1 now returns multiple values. 
> Is this correct?
> Or am I overlooking something?

I think you're missing several things:

* The INLINE declaration won't work;
* There's no BLOCK in the anonymous function, so RETURN-FROMs in the
body break.
* The ARG-LIST trick won't work for non-trivial argument lists.
* The DEFUN isn't at top-level (it's inside a LET), so file
compilation won't notice it (or may not: I think a compiler *could*
notice it since it should be clear that it will always be processed at
load-time).
* What should happen if there are errors?  do you want EXIT-FUNC to be
called or not?
* Finally, I think it's just over-complex for what it does.

Something like this works, I think.

(defmacro define-wrapped-function (name arglist &body body)
  (let ((argsn (make-symbol "ARGS"))
	(abortedn (make-symbol "ABORTED")))
    `(defun ,name (&rest ,argsn)
       (declare (dynamic-extent ,argsn))	;is this safe?
       (let ((,abortedn t))
	 (unwind-protect
	     (progn
	       (entry-handler ',name ,argsn)
	       (multiple-value-prog1
		(block ,name
		  (apply #'(lambda ,arglist ,@body)
			 ,argsn))
		(setf ,abortedn nil)))
	   (exit-handler ',name ,argsn ,abortedn))))))

(defgeneric entry-handler (name args)
  ;; define EQL methods on this if you want.
  (:method ((name t) args)
    (format *trace-output* "~&Enter ~S ~:S~%"
	    name args)))

(defgeneric exit-handler (name args &optional aborted)
  ;; ABORTED will be true if the call is being aborted by a non-local
  ;; exit of some kind.
  ;; define EQL methods on this if you want
  (:method ((name t) args &optional (aborted nil))
    (format *trace-output* "~&Exit ~S ~:S~:[~; (aborted)~]~%"
	    name args aborted)))

I haven't tested this very carefully though.  This is at least as
complicated as your one, of course but I think it handles a lot more
cases...

--tim
From: Peter Szabo
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <40D9CED2.2070308@debitel.net>
I agree, things get more complicated as I assumed. Your code is much 
more improved.
I have to understand and test it. But it realy helps. Thank you very much!
peter
-------------------------------------------------------------------------------
Tim Bradshaw wrote:

>Peter Szabo <······@debitel.net> wrote in message news:<················@debitel.net>...
>  
>
>>Kalles construct is the shortest (so the most elegant) with the problem of
>>declarations and documentation strings. But if I use the hints of James
>>and do a little modification:
>>
>>(defun entry-func ()
>>  (print "in"))
>>
>>(defun exit-func ()
>>  (print "out"))
>>
>>
>>(defmacro mydefun (name arg-list &body body)
>>  "modifies body by first calling entry-foo, than saves what
>>   body yields. Finally exit-foo is called and the saved result is returned"
>>  (declare (inline g))
>>  `(let* ((g (lambda (,@arg-list) ,@body))
>>      (f (defun ,name ,arg-list
>>           (progn
>>         (entry-func)
>>         (multiple-value-prog1 (funcall g ,@arg-list)
>>                       (exit-func))))))
>>     f))
>>
>>than the lambda expression bound to g holds the original body with 
>>declarations and docs.
>>So nothing is lost and multiple-value-prog1 now returns multiple values. 
>>Is this correct?
>>Or am I overlooking something?
>>    
>>
>
>I think you're missing several things:
>
>* The INLINE declaration won't work;
>* There's no BLOCK in the anonymous function, so RETURN-FROMs in the
>body break.
>* The ARG-LIST trick won't work for non-trivial argument lists.
>* The DEFUN isn't at top-level (it's inside a LET), so file
>compilation won't notice it (or may not: I think a compiler *could*
>notice it since it should be clear that it will always be processed at
>load-time).
>* What should happen if there are errors?  do you want EXIT-FUNC to be
>called or not?
>* Finally, I think it's just over-complex for what it does.
>
>Something like this works, I think.
>
>(defmacro define-wrapped-function (name arglist &body body)
>  (let ((argsn (make-symbol "ARGS"))
>	(abortedn (make-symbol "ABORTED")))
>    `(defun ,name (&rest ,argsn)
>       (declare (dynamic-extent ,argsn))	;is this safe?
>       (let ((,abortedn t))
>	 (unwind-protect
>	     (progn
>	       (entry-handler ',name ,argsn)
>	       (multiple-value-prog1
>		(block ,name
>		  (apply #'(lambda ,arglist ,@body)
>			 ,argsn))
>		(setf ,abortedn nil)))
>	   (exit-handler ',name ,argsn ,abortedn))))))
>
>(defgeneric entry-handler (name args)
>  ;; define EQL methods on this if you want.
>  (:method ((name t) args)
>    (format *trace-output* "~&Enter ~S ~:S~%"
>	    name args)))
>
>(defgeneric exit-handler (name args &optional aborted)
>  ;; ABORTED will be true if the call is being aborted by a non-local
>  ;; exit of some kind.
>  ;; define EQL methods on this if you want
>  (:method ((name t) args &optional (aborted nil))
>    (format *trace-output* "~&Exit ~S ~:S~:[~; (aborted)~]~%"
>	    name args aborted)))
>
>I haven't tested this very carefully though.  This is at least as
>complicated as your one, of course but I think it handles a lot more
>cases...
>
>--tim
>  
>
From: Pascal Bourguignon
Subject: Re: Q: to a simple macro
Date: 
Message-ID: <87hdt7wiyv.fsf@thalassa.informatimago.com>
Peter Szabo <······@debitel.net> writes:

> Hi,
> 
> Why is the function g undifiend? Or how to "insert" info
> befor and after running a function (e.g. for debugging)?
> Thanks  in advance!
> 
> (defmacro mydefun (name arg-list &body body)
>   `(let* ((g (defun ,name ,arg-list ,@body))
>             (f  (defun ,name ,arg-list
>                    (let ((res nil))
>                       (print "in")
>                       (setf res (g ,@arg-list))
>                      (print "out")
>                    res))))
>        f))

The operator to use in macro to generate several expressions is progn.

  (defmacro mydefun (name arg-list &body body)
    `(progn
         (defun ,name ,arg-list ,@body))
         (defun ,name ,arg-list
                     (let ((res nil))
                        (print "in")
                        (setf res (g ,@arg-list))
                       (print "out")
                     res)))

Oops you're defining the same function twice?


If the first must be a local function of the second, use label or flet.

(defmacro mydefun (name arg-list &body body)
    `(progn
         (defun ,name ,arg-list
             (label ((g ,arg-list ,@body))
                     (let ((res nil))
                        (print "in")
                        (setf res (g ,@arg-list))
                       (print "out")
                     res)))))

If you must generate two functions, generate two names:

  (defmacro mydefun (name arg-list &body body)
    (let ((name-1 (with-standard-io-syntax 
                      (intern (concatenate 'string "~A-1" name)))))
    `(progn
         (defun ,name-1 ,arg-list ,@body))
         (defun ,name ,arg-list
                     (let ((res nil))
                        (print "in")
                        (setf res (,name-1 ,@arg-list))
                       (print "out")
                     res)))

Finally, you could perhaps just use; (trace myfunction) to obtain the
same results as your macro, and later (untrace myfunction) to revert
to the original situation.

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

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein