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 |

2009-01-16

CLとPOSAアーキテクチャパターン - Layers

| 10:46 | CLとPOSAアーキテクチャパターン - Layers - わだばLisperになる を含むブックマーク はてなブックマーク - CLとPOSAアーキテクチャパターン - Layers - わだばLisperになる

デザインパターンも一通り終えて(多分まだ間違った理解/解釈が多いと思いますが…)defmethodを書く頻度も減り、なんとなく寂しいのでどうにかdefmethodを書く機会が増せないかということで、GoFデザインパターン以外にOOなパターンはないのかと探してみたところ、POSAパターンというのが有名とのこと。

邦訳「ソフトウェアアーキテクチャ—ソフトウェア開発のためのパターン体系」の原書の頭文字からPOSA本と呼ばれているらしく、GoFデザインパターンより大きい枠で捉えたアーキテクチャパターンと呼ばれるもののようです。

オブジェクト倶楽部さんのところにあるPOSAアーキテクチャパターン一覧(PDF)と、八角研究所 : ページが見つかりませんでしたをを眺めつつ考えてみることにしました。

Layersパターン

ということで、POSAパターンの最初はLayersパターンのようなのですが、説明を読んだ限りではネットワーク方面でお馴染のOSI参照モデルみたいなものだろうかと思いました。

基本的に各々のレイヤは隣のレイヤとしか関係を持たせないようにして秩序を与えるという感じかと思いますが、この仕組みをCLでどう表現するか考えてみます。

一般にはクラスの継承関係で表現したりするようですが、どうもぱっとした考えが及ばないので、CLのパッケージ機能で表現してみることにしました。

具体的には、下の層の関数や変数を">"を接頭辞としてカレントパッケージで呼び出せるようにして、下の層との連携を図ってみます。

下記のdefine-layered-packageは、defpackageに加えて下のレイヤのシンボルに接頭辞">"を付けてカレントパッケージに取り込むものです。

(in-package :cl)

(defmacro define-layered-package (name &rest args)
  (let ((base (find :base args :key #'zl:car-safe)))
    (if base
        `(PROG1
           (defpackage ,name ,@(remove :base args :key #'zl:car-safe))
           (eval-when (:compile-toplevel :load-toplevel :execute)
             (do-symbols (x (find-package ,(second base)))
               (when (eq (find-package ,(second base))
                         (symbol-package x))
                 (let ((sym (intern (format nil ">~A" x) ,name)))
                   (when (fboundp x)
                     (if (macro-function x)
                         (setf (macro-function sym)
                               (macro-function x))
                         (setf (symbol-function sym) 
                               (symbol-function x))))
                   (when (boundp x)
                     (setf (symbol-value sym) (symbol-value x)))
                   (setf (symbol-plist sym) (symbol-plist x)))))))
        `(DEFPACKAGE ,name ,@args))))

(export 'define-layered-package)

;; 補助ユーティリティ
(in-package :zl)
(defun car-safe (form)
  (if (consp form)
      (car form)
      form))

試してみる

;; 第1レイヤ
(defpackage :L-1 (:use :cl))
(in-package :L-1)

(defun fib (n a1 a2)
  (if (< n 2)
      a1
      (fib (1- n)
           (+ a1 a2)
           a1)))

;; 第2レイヤ
(define-layered-package :L-2
  (:use :cl)
  (:base :L-1))

(in-package :L-2)

(defun fib (n)
  (>fib n 1 0))

(fib 100)
;=>354224848179261915075

微妙に使えるような使えないような、ぱっとしない感じですが、一応層を分けて、隣接としか関係を持たせないという秩序立てはできる気はするので良しとします。

S式Dylanの処理系

| 07:32 | S式Dylanの処理系 - わだばLisperになる を含むブックマーク はてなブックマーク - S式Dylanの処理系 - わだばLisperになる

大分前に試していてすっかり書くのを忘れていたのですが、Dylanは当初から仕様はオープンだったということもあり、登場時に各所で実験的に作成されたインタープリタがあります。

代表的なものとして、Thomasがあり、当時のScheme処理系の上で動くものでした。

現在でもソースは入手できるので頑張れば今でも動くとは思うのですが、R3RS位なので自分は良く分からず、上手く動かせないでいました。

というところで放置していたのですが、旧MacOS用にコンパイルされたものが配布されているのを発見したので早速MacOSX上のClassic環境で動かしてみたところ素直に動くので記念エントリです。

から入手できます。

(define-method fib ((n <number>))
  (cond ((< n 2) n)
        (else: (+ (fib (- n 2))
                  (fib (- n 1))))))
(fib 10)
;=> 55

(define-class <foo> (<object>)
  x
 (y init-value: 0 init-keyword: y:))

(define-class <bar> (<foo>)
 (z init-function: (method () 333)))

(bind ((foo (make <foo> y: 8)))
  ((setter x) foo 3)
  (list (x foo) (y foo)))
;=> (3 8)

(z (make <bar>))
;=> 333

という風に書いたり試したりして遊べます。

MacOSXのClassic環境自体絶滅しそうですが、興味のある方は試してみてはいかがでしょうか。

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20090116