Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

A trivial piece of code that a candidate should be able to write as quickly as they can type on a computer or write on the board designed to test that (1) they can write basic code and (2) they've written enough code that trivial problems are trivial. Jeff Atwood coined the phrase [1] and gave the classic example:

   Write a program that prints the numbers from 1 to 100. But for multiples 
   of three print "Fizz" instead of the number and for the multiples of five
   print "Buzz". For numbers which are multiples of both three and five print
   "FizzBuzz".
[1] http://www.codinghorror.com/blog/2007/02/why-cant-programmer...


Can someone tell me a lispier way of doing this than

  (dotimes (n 100)
	   (cond ((= 0 n))
		 ((and (= 0 (mod n 3))(= 0 (mod n 5)))
		  (format t "~a: Fizz Buzz!~%" n))
		 ((= 0 (mod n 3))
		  (format t "~a: Fizz!~%" n))
		 ((= 0 (mod n 5))
		  (format t "~a: Buzz!~%" n))
		 (t (format t "~a~%" n))))


Surely, the lispiest way is to write an interpreter! Write a function fizzbuzz-eval so that the following is a solution (left as an exercise). ;)

    (fizzbuzz-eval
     100
     '(((3 5) (print "FizzBuzz"))
       ((3)   (print "Fizz"))
       ((5)   (print "Buzz"))
       (()    print-number)))


Here's a macro. There's some issues :) The biggest one is you have to make sure to put the multiple divisors list first.

The call is

  (fizzbuzz (100 (((3 5) "fizzbuzz")(3 "fizz")(5 "buzz"))))

  (defun make-cond (item)
  (let ((divisors (first item))
	(exclamation (second item)))
    (if (listp divisors)
	(let ((div1 (first divisors))
	      (div2 (second divisors)))
	  `((and (= 0 (mod n ,div1)) (= 0 (mod n ,div2)))
	    (format t "~a: ~a~%" n ,exclamation)))
      `((= 0 (mod n ,divisors)) ;else
	(format t "~a: ~a~%" n ,exclamation)))))

  (defmacro fizzbuzz (params-list)
  (destructuring-bind (num-to req-list) params-list
    (let ((cond-list '(((= 0 n)))))
      (loop for item in req-list do
	    (push (make-cond item) cond-list))
      `(dotimes (n ,num-to)
	 (cond ,@(reverse
		  (push '(t (format t "~a~%" n))
			cond-list)))))))


Hehe. That's quite a monster. I'll try to be a bit more helpful.

1. Use loop instead of dotimes so you can make the index range over 1-100 instead of 0-99.

2. Factor out the string calculation so you only need one print statement.

3. Maybe use zerop.

4. Don't write ")(". Use a space in between.

Example:

    (loop for n from 1 to 100
          do (format t "~a~%"
                     (cond
                      ((and (zerop (mod n 3))
                            (zerop (mod n 5)))
                       "FizzBuzz")
                      ((zerop (mod n 3)) "Fizz")
                      ((zerop (mod n 5)) "Buzz")
                      (t (format nil "~a" n)))))


Thanks!

With the macro you can use arbitrary divisors though ;)

Any desire to refactor that beast?




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: