Futureパターン

Future - qnzm.log(クニジマログ)をやってみた。
一応書いたけど中途半端だし、いまいち。

元のサンプルがOOPなんだけど、そのままじゃつまらないからLispっぽい方法はないものかと思ったんだけど思いつかず。。。
それならプロキシを生成する部分をマクロで自動的にやらせれば、、、と試したけど僕にはムリ。
収穫はメタオブジェクトプロトコルを少しだけ垣間見たことくらいか。

MOPで覚えたこと
メタオブジェクトプロトコル関連はsbclならsb-mopにある

クラスのスロット一覧取得、メソッドの取得はこんな感じ。

CL-USER> (defclass cls () 
       ((a :accessor cls-a)
        (b :accessor cls-b)))
#<STANDARD-CLASS CLS>
CL-USER> (defmethod foo ((o cls))
       (print "foo"))
STYLE-WARNING: implicitly creating new generic function FOO
#<STANDARD-METHOD FOO (CLS) {AA53DB1}>
CL-USER> (sb-mop:class-slots (find-class 'cls))
(#<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION A>
 #<SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION B>)
CL-USER> (find-method #'foo nil (list (find-class 'cls)) t)
#<STANDARD-METHOD FOO (CLS) {AA53DB1}>

でFutureパターン。
MOPに引っかかりまくって疲れちゃって中途半端です。
ちゃんと動いてるのかテストもしてない。
with-lockとwaitforはいつもと同じ。
httpでのrssの取得はdrakma、xmlのパースはs-xmlを使った。

drakma:http-requestでrssを取得するときに:external-format-in :external-format-outを指定しないと文字化けすることがあるみたいなので注意。

rssをS式にまで落としたところで力尽きた。タイトルの抽出までやりたかったんだけど。

(defclass rss ()
  ((content :accessor content :initform nil :initarg :content)))

(defmethod rss-get-content ((r rss))
  (print "rss-get-content")
  (content r))

(defclass rss-proxy (rss)
  ((rss :accessor rss :initform nil)
   (sm :accessor semaphore)))

(defmethod initialize-instance :after ((p rss-proxy) &rest intargs)
  (setf (semaphore p) (sb-thread::make-semaphore :name (symbol-name (gensym))))
  (sb-thread::signal-semaphore (semaphore p)))

(defmethod rss-proxy-set-rss((p rss-proxy) rss)
  (with-lock  
   (semaphore p)
   (setf (rss p) rss)))

(defmethod rss-get-content ((p rss-proxy))
  (print "proxy rss-get-content")
  (waitfor (semaphore p)
        (rss p)
       (rss-get-content (rss p))))

(require 'drakma)
(require 's-xml)

(defun get-rss-list(&rest urls)
  (mapcar #'(lambda (url)
          (let ((tl-url url)
            (p (make-instance 'rss-proxy)))
        (sb-thread:make-thread 
         #'(lambda ()
             (rss-proxy-set-rss p
                    (make-instance 'rss :content 
                               (s-xml:parse-xml-string (drakma:http-request tl-url :external-format-in :utf-8 :external-format-out :utf-8))))))
          p))
      urls))

(mapcar #'(lambda (p)
        (format t "content --~A~%" (rss-get-content p)))
    (cl-concurrent:get-rss-list 
     "http://headlines.yahoo.co.jp/rss/rps_dom.xml" 
     "http://news.goo.ne.jp/rss/topstories/gootop/index.rdf" 
     "http://rss.rssad.jp/rss/livedoornews/topics/rss.xml"))