From: Brian Adkins on
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
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
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
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

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>