2008-11-11
メソッドコンビネーションでFizzBuzz (2)
CLOS |
前回、メソッド修飾子を数値で表現して、それでFizzBuzzできるんじゃないかと考えてみましたが、CLtL2のdefine-method-combinationの説明用のコードが元ネタになります。
内容としては、まず、メソッド修飾子をmethod-qualifiersで集めて、修飾子が数値なので順番にソートしたものが優先順位として並べられるというものみたいです。
修飾子は、
(method-qualifiers (find-method #'fizzbuzz '(1) (list (find-class 'one))))
みたいにして取得できます。
それで、前回と比べてあまりかわりばえしないのですが、
(defclass one () ()) (defmethod fizzbuzz 1 ((obj one)) (format t "~A~%" 1)) (defclass two (one) ()) (defmethod fizzbuzz 2 ((obj two)) (format t "~A~%" 2))
みたいな定義を作って行くことになります。
しかし、クラスと修飾子の意味が被ってるので、ぱっとしないのがくやしい。
ちなみに、修飾子で順番を決めているので、:most-specific-firstであろうが、:most-specific-lastを指定しようが、1から順番に実行されます。
;;; ;;; 動作 ;;; ;; 総称関数定義 (defgeneric fizzbuzz (cls) (:method-combination fizzbuzz)) (loop :for i :from 1 :to 100 :do (make-fizzbuzz#2 i)) ;; 実行 (fizzbuzz (make-instance '|ONE HUNDRED|)) ... 82 83 Fizz Buzz 86 Fizz 88 89 Fizz Buzz 91 92 Fizz 94 Buzz Fizz 97 98 Fizz Buzz
;; メソッドコンビネーションの定義 CLtL2参照(というかそのまま) (define-method-combination fizzbuzz () ((methods positive-integer-qualifier-p)) `(progn ,@(mapcar #'(lambda (method) `(call-method ,method ())) (stable-sort methods #'< :key #'(lambda (method) (first (method-qualifiers method))))))) (defun positive-integer-qualifier-p (method-qualifiers) (and (= (length method-qualifiers) 1) (typep (first method-qualifiers) '(integer 0 *)))) ;; 型で振り分けるので型を定義 (deftype fizz () (let ((g (gensym))) (setf (symbol-function g) (lambda (x) (zerop (rem x 3)))) `(satisfies ,g))) (deftype buzz () (let ((g (gensym))) (setf (symbol-function g) (lambda (x) (zerop (rem x 5)))) `(satisfies ,g))) (deftype fizzbuzz () '(and fizz buzz)) ;; 99 -> NINETY-NINE みたいなものを作成する (defun make-roman-number-symbol (n) (values (intern (format nil "~:@(~R~)" n)))) (defmacro make-fizzbuzz#2 (n) `(eval `(progn (defclass ,#1=(make-roman-number-symbol ,n) ,(if (zerop (1- ,n)) () `(,(make-roman-number-symbol (1- ,n)))) () ) (defmethod fizzbuzz ,(eval ,n) ((cls ,#1#)) (format T ,@(typecase ,n (fizzbuzz (list "Fizz Buzz~%")) (buzz (list "Buzz~%")) (fizz (list "Fizz~%")) (otherwise (list "~A~%" ,n))))))))
■