Subject: Re: A style question
From: rpw3@rpw3.org (Rob Warnock)
Date: Wed, 28 Feb 2007 22:29:20 -0600
Newsgroups: comp.lang.lisp
Message-ID: <JrSdndwsgPE9y3vYnZ2dnUVZ_rmdnZ2d@speakeasy.net>
<nallen05@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > This one is both efficient -- *no* MOD calls at all! --
| > *and* so ugly only a parent could love it:  ;-}  ;-}
| >
| >     (defun fizz-buzz (n)
| >       (loop for i from 1 to n
| > 	    and three-p in '#3=(nil nil t . #3#)
| > 	    and five-p in '#5=(nil nil nil nil t . #5#)
| > 	do ...
| 
| This is awsome, Rob ;-) But I can make one that's faster AND uglier!
| 
| (defmacro def-fizz-buzz ()
|   (let (l)
|     (do* ((i 1 (incf i))
| 	  (m3p (zerop (mod i 3))
| 	       (zerop (mod i 3)))
| 	  (m5p (zerop (mod i 5))
| 	       (zerop (mod i 5))))
| 	 ((> i 15))
|       (setq l
| 	    (list*  `(print ,(cond ((and m3p m5p) "FizzBuzz")
| 				   (m3p           "Buzz")
| 				   (m5p           "Fizz")
| 				   (t             'y)))
| 		    '(when (> y x) (return))
| 		    '(incf y)
| 		    l)))
|     `(defun fizz-buzz (x)
|       (let ((y 0))
| 	(loop ,@(reverse l))))))
+---------------

Yes!! *That's* how to use macros to write code for you!!  ;-}

One minor tweak -- instead of:

    (INCF Y)
    (WHEN (> Y X) (RETURN))

you could use:
  	  
    (WHEN (> (INCF Y) X) (RETURN))

Another really minor tweak -- in the DO* variable bindings,
instead of (M3P (ZEROP (MOD I 3)) (ZEROP (MOD I 3)) you can
write (M3P #1=(ZEROP (MOD I 3)) #1#).

Now for *lots* of extra credit...  ;-}  ;-}

Write the general version of DEF-FIZZ-BUZZ that accepts a
function name (so we can tell them apart) and an alist of primes
and strings, and emits similarly-correct/fast code. E.g., the 
example we've been using all along would be generated like so:

    (def-fizz-buzz 'fizz-buzz '((3 "Fizz") (5 "Buzz")))


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607