From: job-271842874 on 27 Feb 2007 20:12 A friend passed on an article regarding the difficulty job candidates had in producing even simple programs (simple as in should take a minute or less). One example was a program to print the numbers 1 to 100 except that "Fizz" should be substituted for numbers divisible by 3, "Buzz" should be substituted for numbers divisible by 5, and "FizzBuzz" should be substituted for numbers divisible by both 3 and 5. So, having received my "ANSI Common Lisp" and "Practical Common Lisp" books two days ago (still waiting for "Structure and Interpretation of Computer Programs") and having a *couple hours* of Lisp under my belt, I cranked out a Lisp version. It seems a bit clunky, so I thought I'd see if anyone had suggestions for improvements. Here's a Ruby version for comparison: def fizz_buzz n 1.upto(n) do |i| print "Fizz" if fizz = (i % 3) == 0 print "Buzz" if buzz = (i % 5) == 0 puts fizz || buzz ? "" : i end end fizz_buzz 100 and the Lisp version (defun fizz-buzz (n) (do ((i 1 (+ i 1))) ((> i n)) (let ((fizz (= 0 (mod i 3))) (buzz (= 0 (mod i 5)))) (if fizz (format t "Fizz")) (if buzz (format t "Buzz")) (format t "~A~%" (if (or fizz buzz) "" i))))) (fizz-buzz 100) By the way, it seems more folks recommend starting with "Practical Common Lisp" instead of "ANSI Common Lisp" (when both are mentioned), but being a newbie myself, it seems that the latter is a better introduction to the language. Brian
From: Frank Buss on 27 Feb 2007 20:38 job-271842874(a)craigslist.org wrote: > I cranked out a Lisp version. It seems a bit clunky, so I thought I'd see > if anyone had suggestions for improvements. looks ok, but I would use loop and organize the body of the loop a bit different: (defun fizz-buzz (n) (loop for i from 1 to n for fizz = (zerop (mod i 3)) for buzz = (zerop (mod i 5)) do (when fizz (princ "Fizz")) (when buzz (princ "Buzz")) (when (not (or fizz buzz)) (princ i)) (terpri))) -- Frank Buss, fb(a)frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de
From: job-271842874 on 27 Feb 2007 21:02 Frank Buss wrote: > job-271842874(a)craigslist.org wrote: > >> I cranked out a Lisp version. It seems a bit clunky, so I thought I'd see >> if anyone had suggestions for improvements. > > looks ok, but I would use loop and organize the body of the loop a bit > different: > > (defun fizz-buzz (n) > (loop for i from 1 to n > for fizz = (zerop (mod i 3)) > for buzz = (zerop (mod i 5)) do > (when fizz (princ "Fizz")) > (when buzz (princ "Buzz")) > (when (not (or fizz buzz)) (princ i)) > (terpri))) > Thanks. Some questions/comments: 1) In "ANSI Common Lisp", Graham makes the following comments: "The loop macro was originally designed to help inexperienced Lisp users write iterative code...Unfortunately, loop is more like English than its designers ever intended...to understand it in the abstract is almost impossible...For such reasons, the use of loop cannot be recommended." Is this a minority view? One of the things that attracted me to Lisp was the simplicity, consistency, etc. of the language, so when I read the above, it seemed reasonable. 2) Thanks for the zerop tip. I like (zerop (mod m n)) better than (= 0 (mod m n)) 3) Any reason why you chose (when fizz (princ "Fizz")) instead of (if fizz (princ "Fizz")) ? 4) Curious about the history of "terpri" - I guess it's shorter than "newline" but not very intuitive :) I'm really enjoying learning Lisp. I realize at this stage I still have some "the grass is greener" and "oh cool, something new to learn!" influences, but I expect as that wears off the merits of the language will continue to shine through. Brian
From: Lars Rune Nøstdal on 27 Feb 2007 21:08 My first try: (loop :for i :from 1 :upto 100 :doing (cond ((= 0 (mod i 3) (mod i 5)) (write-line "FizzBuzz")) ((= 0 (mod i 3)) (write-line "Fizz")) ((= 0 (mod i 5)) (write-line "Buzz")) (t (format t "~A~%" i)))) ...then.. (loop :for i :from 1 :upto 100 :doing (let ((fizz-or-buzz nil)) (when (= 0 (mod i 3)) (princ "Fizz") (setf fizz-or-buzz t)) (when (= 0 (mod i 5)) (princ "Buzz") (setf fizz-or-buzz t)) (unless fizz-or-buzz (princ i)) (terpri))) I suppose one could write a version of cond with a :when-no-clauses clause or something to do some hiding. Maybe `loop' already has something? Well, gonna try: (defmacro cond* (&body body) `(let ((any-clause-p nil)) ,@(mapcar (lambda (clause-form) (if (eq :unless-till-now (first clause-form)) `(unless any-clause-p ,(second clause-form)) `(when ,(first clause-form) ,(second clause-form) (setf any-clause-p t)))) body))) (loop :for i :from 1 :upto 100 :doing (cond* ((= 0 (mod i 3)) (princ "Fizz")) ((= 0 (mod i 5)) (princ "Buzz")) (:unless-till-now (princ i))) (terpri)) ":unless-till-now" .. not sure about the name, but I'm thinking "unless any clause has been true up to now". So it works in the middle too. Now, hoping that I've not made too many mistakes; is there anyone who would like to pay me to do tasks like this? :} -- Lars Rune Nøstdal http://nostdal.org/
From: Paul Wallich on 27 Feb 2007 21:21
job-271842874(a)craigslist.org wrote: > A friend passed on an article regarding the difficulty job candidates > had in producing even simple programs (simple as in should take a minute > or less). One example was a program to print the numbers 1 to 100 except > that "Fizz" should be substituted for numbers divisible by 3, "Buzz" > should be substituted for numbers divisible by 5, and "FizzBuzz" should > be substituted for numbers divisible by both 3 and 5. > > So, having received my "ANSI Common Lisp" and "Practical Common Lisp" > books two days ago (still waiting for "Structure and Interpretation of > Computer Programs") and having a *couple hours* of Lisp under my belt, I > cranked out a Lisp version. It seems a bit clunky, so I thought I'd see > if anyone had suggestions for improvements. > > Here's a Ruby version for comparison: > > def fizz_buzz n > 1.upto(n) do |i| > print "Fizz" if fizz = (i % 3) == 0 > print "Buzz" if buzz = (i % 5) == 0 > puts fizz || buzz ? "" : i > end > end > > fizz_buzz 100 > > and the Lisp version > > (defun fizz-buzz (n) > (do ((i 1 (+ i 1))) > ((> i n)) > (let > ((fizz (= 0 (mod i 3))) > (buzz (= 0 (mod i 5)))) > (if fizz (format t "Fizz")) > (if buzz (format t "Buzz")) > (format t "~A~%" > (if (or fizz buzz) "" i))))) In both cases, what the local variables add in supposed elegance seems to me lost by the clunkiness of setting them in the first place (which you haven't done correctly). I'd probably brute-force the problem with a simple cond with a nested conditions, along the lines of (cond ((zerop (mod i 5)) (cond ((zerop (mod i 3)) (print "FizzBuzz")) (t (print "Buzz")))) ((zerop (mod i 3)) (print "Fizz")) (t (print i))) Someone else can do the loop version, the version with a macro that generates any possible fizz-buzz function of two small integers, the ver |