commonlispでFizzbuzz問題を解いてみる

最初の実装

まずはシンプルなFizzBuzz実装から始める。1から100までの数字を列挙し以下の条件に基づいて出力する。

  • 3で割り切れる場合は "Fizz"
  • 5で割り切れる場合は "Buzz"
(dotimes (i 100)
  (let* ((n (1+ i))
         (fizz (if (zerop (mod n 3)) "Fizz" ""))
         (buzz (if (zerop (mod n 5)) "Buzz" ""))
         (fizzbuzz (concatenate 'string fizz buzz)))
    (format t "~a~%" (if (string= fizzbuzz "") n fizzbuzz))))

これでFizzBuzzの基本的な実装が完成した。ここからコードを拡張する。

拡張版実装

こちらではルールを柔軟に追加できるようにした。

(defun print_fizzbuzz (i rules)
  (let* ((n (1+ i))
         (result (reduce (lambda (acc rule)
                           (let ((condition (first rule))
                                 (output (second rule)))
                             (if (funcall condition n)
                                 (concatenate 'string acc output)
                                 acc)))
                         rules
                         :initial-value "")))
    (if (string= result "")
        n
        result)))

(defun print_fizzbuzz_with_rules (limit rules)
  (dotimes (i limit)
    (let ((result (print_fizzbuzz i rules)))
      (format t "~a~%" result))))

(let ((rules (list (list #'(lambda (n) (zerop (mod n 3))) "Fizz")
                   (list #'(lambda (n) (zerop (mod n 5))) "Buzz"))))
  (print_fizzbuzz_with_rules 100 rules))

拡張版では rules 変数にルールを追加することで、例えば「7で割り切れる時は "hoge" を返す」といった機能を簡単に追加できるようになった。 また表示とルールを分離することでテストしやすいコードになった。