From: Brian Adkins on 1 Mar 2007 12:31 Rob Warnock wrote: > lojic <lojicdotcom(a)gmail.com> wrote: > +--------------- > | r...(a)rpw3.org (Rob Warnock) wrote: > | > 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"))) > | > | That goes back to my earlier post of the following generalized > | solution: > | > | (defun fizz-buzz (n lst) > | (do ((i 1 (+ i 1))) > | ((> i n)) > | (let > | ((fizzed nil)) > | (dolist (obj lst) > | (let ((a (car obj)) > | (str (car (cdr obj)))) > | (when (zerop (mod i a)) > | (princ str) > | (setf fizzed t)))) > | (if (not fizzed) > | (princ i)) > | (terpri)))) > | > | (fizz-buzz 15 '((3 "Fizz") (5 "Buzz"))) > +--------------- > > That's fine, for a run-time function. [I had a bit of a chuckle at what > (fizz-buzz 100 '((2 "Burp")(3 "Fizz") (5 "Buzz")(7 "Bang")(11 "Boom!"))) > outputs...] > > +--------------- > | This was my off-the-cuff approach from a non-Lisp background. > +--------------- > > It's actually reasonably "Lispy" as is. Thanks for the tips below. When I said, "non-Lisp background" I wasn't referring to the Lispyness of the implementation of the function (which I kind of slapped together with the tools I've accumulated through p.36 of Graham's book), but the use of a runtime function vs. a macro. > Oh, sure, you might use [tips deleted for brevity] > +--------------- > | I would like to see a macro-ized version... > +--------------- > > Did you see <nallen05(a)gmail.com>'s version for the case of a > hard-coded '((3 "Fizz") (5 "Buzz")) list? Actually no :( I searched for posts by nallen05 and didn't see any on this thread, but Bellsouth had newsgroup server issues yesterday, they may have dropped a few posts. I'll try searching Google groups for it. > +--------------- > | ...and get some feedback from the group regarding the > | appropriateness of macros in this case vs. a simple > | function as in the above. > +--------------- > > A macro would fix the LIST at macroexpansion time, which allows > the macro to potentially generate better code [possibly *much* > better code, as <nallen05(a)gmail.com> showed], but loses the > runtime flexibility of your above function. > > One hybrid that might be useful would be a function that > looked at N and the length of LIST (and all the CARs) and > decided whether to do it the straightforward way (as above) > or whether to use an initialization step to pre-bake some > auxiliary tables to speed up the computation [e.g., like > the circular lists in my version, to avoid MOD, but computed > at runtime]. Interesting > -Rob > > ----- > Rob Warnock <rpw3(a)rpw3.org> > 627 26th Avenue <URL:http://rpw3.org/> > San Mateo, CA 94403 (650)572-2607 >
From: Pillsy on 1 Mar 2007 15:04 On Mar 1, 12:14 am, Vassil Nikolov <vnikolov+use...(a)pobox.com> wrote: > On 28 Feb 2007 12:01:22 -0800, "Pillsy" <pillsb...(a)gmail.com> said: > | ... > | (apply #'format t "~@{ ~2@{~D ~}~^~*Fizz ~D ~*Buzz~ > | ~*Fizz ~2@{~D ~} ~*Buzz ~D ~*Fizz~ > | ~2@{~D ~} ~*FizzBuzz ~%~}" > | (loop > | :for i :from 1 to 100 > | :collect i)) > But you want it to work for arbitrarily large values of 100... Good point! (setf (symbol-value '|100|) 100) (defun fb (stream arg colonp atsignp) (declare (ignore arg colonp atsignp)) (incf *count*) (format stream "~[Fizz~[Buzz~:;~]~^~:;~[Buzz~^~:;~D~]~]" (mod *count* 3) (mod *count* 5) *count*)) (let ((*count* 0)) (format t "~v{~/fb/~%~}" |100| '#1=((). #1#))) And I think this one actually works, too! :D Cheers, Pillsy
From: Pillsy on 1 Mar 2007 15:06 On Mar 1, 3:04 pm, "Pillsy" <pillsb...(a)gmail.com> wrote: > On Mar 1, 12:14 am, Vassil Nikolov <vnikolov+use...(a)pobox.com> wrote: > > > On 28 Feb 2007 12:01:22 -0800, "Pillsy" <pillsb...(a)gmail.com> said: > > | ... > > | (apply #'format t "~@{ ~2@{~D ~}~^~*Fizz ~D ~*Buzz~ > > | ~*Fizz ~2@{~D ~} ~*Buzz ~D ~*Fizz~ > > | ~2@{~D ~} ~*FizzBuzz ~%~}" > > | (loop > > | :for i :from 1 to 100 > > | :collect i)) > > But you want it to work for arbitrarily large values of 100... > > Good point! > > (setf (symbol-value '|100|) 100) > > (defun fb (stream arg colonp atsignp) > (declare (ignore arg colonp atsignp)) > (incf *count*) > (format stream "~[Fizz~[Buzz~:;~]~^~:;~[Buzz~^~:;~D~]~]" > (mod *count* 3) (mod *count* 5) *count*)) > > (let ((*count* 0)) > (format t "~v{~/fb/~%~}" |100| '#1=((). #1#))) > > And I think this one actually works, too! :D Well, as long as I copy-and-paste right, and don't leave the (defvar *count*) out! Cheers, Pillsy
From: Thomas Bakketun on 1 Mar 2007 17:51 Richard M Kreuter wrote: > Here's one that avoids the explicit FizzBuzz, and adds /seven/ > squiggles to my first stab: > > (dotimes (i 100) > (format t "~[~[~3@*~A~A~:;~3@*~A~]~:;~[~4@*~A~:;~D~]~]~%" > (mod i 3) (mod i 5) i "Fizz" "Buzz")) > > Better? Is this the shortest version possible? (defun fizz-buzz () (loop for i from 1 to 100 do (format t "~&~[Fizz~]~[Buzz~:;~0@*~[~:;~*~A~]~]" (mod i 3) (mod i 5) i)))
From: nallen05 on 1 Mar 2007 20:21
Rob Warnock wrote: > Ken Tilton <kentilton(a)gmail.com> wrote: > +--------------- > | ps. Me, I am not starting until we get the functional requirements > | cleared up. k > +--------------- > > See my reply to <nallen05(a)gmail.com>'s MOD-free code-generating macro, > or take this instead: > > Macro DEF-FIZZ-BUZZ -- Define a "fizz-buzz"-generating function > > Syntax: > def-fizz-buzz fname alist ==> fname > > Arguments and Values: > fname -- A symbol, the name of the function to be defined (as by DEFUN). > > alist -- an association list, whose keys are prime integers > 1 > and whose values are strings. > > Description: > > DEF-FIZZ-BUZZ defines a function named FNAME of one argument, > a positive integer. When called with an argument (say) N, FNAME > will print each positive integer starting with 1 below N, followed > by a newline, except that if any of the keys of the ALIST evenly > divide the current integer, then the corresponding string value(s) > of the key(s) dividing the current integer will be printed instead > of the integer itself. Note: If multiple keys divide the current > integer, all of the corresponding string values will be printed, > in the same order as the elements of the ALIST. Only one copy > of any string value will be printed for any current integer. > > Examples: > > (def-fizz-buzz 'fizz-buzz '((3 . "Fizz") (5 . "Buzz"))) ==> FIZZ-BUZZ > > (fizz-buzz 22) > >> 1 > >> 2 > >> Fizz > >> 4 > >> Buzz > >> Fizz > >> 7 > >> 8 > >> Fizz > >> Buzz > >> 11 > >> Fizz > >> 13 > >> 14 > >> FizzBuzz > >> 16 > >> 17 > >> Fizz > >> 19 > >> Buzz > >> Fizz > >> 22 > ==> NIL > > (def-fizz-buzz 'very-fizzy > '((2 . "Burp") (3 . "Fizz") (5 . "Buzz") (7 . "Bang"))) > ==> VERY-FIZZY > > (very-fizzy 16) > >> 1 > >> Burp > >> Fizz > >> Burp > >> Buzz > >> BurpFizz > >> Bang > >> Burp > >> Fizz > >> BurpBuzz > >> 11 > >> BurpFizz > >> 13 > >> BurpBang > >> FizzBuzz > >> Burp > ==> NIL > > There's your spec. Where's your code? ;-} ok, here ya go... (defmacro def-fizz-buzz (name alist) (let (l (lcd (reduce #'* alist :key #'first))) (do ((n 1 (incf n))) ((> n lcd)) (push '(terpri) l) (let ((old l)) (dolist (a alist) (when (zerop (mod n (first a))) (push `(princ ,(rest a)) l))) (when (eq l old) (push '(princ y) l))) (push '(when (> (incf y) x) (return)) l)) `(defun ,name (x) (let ((y 1)) (loop ,@(nreverse l)))))) CL-USER> (macroexpand-1 '(def-fizz-buzz very-fizzy ((2 . "Burp") (3 . "Fizz") (5 . "Buzz")))) (DEFUN VERY-FIZZY (X) (LET ((Y 1)) (LOOP (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Fizz") (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Fizz") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC Y) (WHEN (> (INCF Y) X) (RETURN)) (TERPRI) (PRINC "Burp") (PRINC "Fizz") (PRINC "Buzz") (WHEN (> (INCF Y) X) (RETURN))))) T CL-USER> |