Subject: Re: macro question
From: Erik Naggum <erik@naggum.net>
Date: Sun, 10 Mar 2002 19:54:35 GMT
Newsgroups: comp.lang.lisp
Message-ID: <3224778884977282@naggum.net>

* Rolf Wester <rolf.wester@t-online.de>
| This would be true for you but not necessaryly for a lisp beginner like
| me.  At present this is a problem for me. I know C++ well enough to be
| able to do my work in a reasonable or at least predictable time. At
| present I don't have the same confidence in my Lisp skills.

  In that case, it is encouraging that you try Common Lisp.  (I started to
  use Common Lisp because C++ was just way too painful, and in the learning
  period, sustained myself as a journalist/columnist just to get away from
  programming computers for pay for a few years.  It was that bad. :)

| I guess I should learn about IA32 assembler.

  If you do, what you really need is a macro language that _works_, so
  producing assembly code using Common Lisp is the only way to go.

| I read about compiler-maros before but have no clear understanding what
| this is.  Can you give me a link to somewhere I can learn more about it?

  Not really.  They can be used to turn a function call into a macro call,
  such that the call is effectively expanded inline.  Suppose that your
  maxwell-v-c1-c2 function does (* c1 v v (exp (* c2 v v ))), and that
  calling a function with three arguments would lose the type information
  the compiler is able to infer or has to been taught by you, and might
  even have to generic floating-point operations.  If you had this function
  and decided that it would make sense to optimize this call, you could do

(defun maxwell-v-c1-c2 (v c1 c2)
  (declare (double-float v c1 c2)
	   (optimize (speed 3) (safety 0) (debug 0)))
  (* c1 v v (exp (* c2 v v))))

(defun maxwell-caller (v temp m)
  (declare (double-float v temp m)
	   (optimize (speed 3) (safety 0) (debug 0)))
  (let ((c1 (* 4.0d0 dpi (expt (/ m (* 2.0d0 dpi +kB+ temp)) 1.5d0)))
	(c2 (/ (* -1.0d0 m) (* 2.0d0 +kB+ temp))))
    (maxwell-v-c1-c2 v c1 c2)))

  This would need to box the double-float arguments, but could benefit from
  the fast, pure assembly code that is in the inner function.

(define-compiler-macro maxwell-v-c1-c2 (v c1 c2)
  `(* c1 v v (exp (* c2 v v))))

  This is an example of how to use compiler macros to inline user functions
  such that type inference and declarations still work.  Some Common Lisp
  environments provide that functionality with a declaration to inline a
  particular function, but that is neither necessarily portable nor
  actually as effective.

  The biggest advantage of a compiler macro, however, is how it may be used
  to change a function call into something else.  Suppose you have a
  function that takes any number of parameters, but it has a simple
  definition for, say, 0, 1, and 2 arguments, like + does.

(define-compiler-macro + (&whole form
			  &optional (arg-1 nil arg-1-p)
				    (arg-2 nil arg-2-p)
			  &rest arguments)
  (cond ((not arg-1-p) 0)
	((not arg-2-p) arg-1)
	((not arguments) `(internal-2-arg-+ arg-1 arg-2))
	(t form)))

  A macro cannot decline to expand, but a compiler-macro can do just that
  by returning the whole form unchanged.

  This may or may not help...

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.