Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-11-16

MOPでFizzBuzz (1.5)

| 02:49 | MOPでFizzBuzz (1.5) - わだばLisperになる を含むブックマーク はてなブックマーク - MOPでFizzBuzz (1.5) - わだばLisperになる

非常にどうでも良いところなのですが、前回のmake-instanceでFizzBuzzでは、

  1. counterを外からリセットできない
  2. 数値が確認できない

という心残りがありました。

という訳で、色々策を考えてみたのですが、メタクラスのスロットをクラス変数にして、インスタンス間で共有し、それをいじることにしてみました。

それと数値の確認については、print-objectを設定。

また、MOPについては、ANSI CLで決まっていないだけに、処理系依存なところもあるのですが、これを吸収するようなパッケージがあるので利用してみました。

カウンタのリセットについては、もっと真っ当な方法がある気がしてならないのですが、なんにしろ真面目なプログラムではないので、ちゃんとした例が書けるようになりたいです(笑)

;; メタクラス
(defclass fizzbuzz-meta (standard-class)
  ((counter :initform 0 :allocation :class)))

;; 型を定義して型で振り分けてみる
(defun fizzp (n) (zerop (rem n 3)))
(deftype fizz () '(satisfies fizzp))
(defun buzzp (n) (zerop (rem n 5)))
(deftype buzz () '(satisfies buzzp))
(deftype fizzbuzz () '(and fizz buzz))

(defmethod make-instance :around ((metaclass fizzbuzz-meta) &key)
  (with-slots (counter) metaclass
    (incf counter)
    (typecase counter
      (fizzbuzz "Fizz Buzz")
      (fizz "Fizz")
      (buzz "Buzz")
      (otherwise (call-next-method)))))

(defmethod c2mop:validate-superclass ((class fizzbuzz-meta)
                                      (super standard-class))
  'T)

(defclass foo () ()
  (:metaclass fizzbuzz-meta))

(let ((cnt (make-instance 'fizzbuzz-meta)))
  (defmethod print-object ((obj foo) stream)
    (print-unreadable-object (obj stream)
      (format stream "~A ~A" (type-of obj)
              (slot-value cnt 'counter))))
  (defun reset-fizzbuzz-counter ()
    (setf (slot-value cnt 'counter) 0)))

;; 実行
(dotimes (i 100)
  (format T "~A~%" (make-instance 'foo)))

;; カウンタリセット
(reset-fizzbuzz-counter)

;>>>
#<FOO 1>
#<FOO 2>
Fizz
#<FOO 4>
Buzz
Fizz
#<FOO 7>
#<FOO 8>
Fizz
Buzz
#<FOO 11>
Fizz
#<FOO 13>
#<FOO 14>
Fizz Buzz
#<FOO 16>
#<FOO 17>
Fizz
#<FOO 19>
Buzz
Fizz
#<FOO 22>
#<FOO 23>
...