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 |

2011-01-11

パッケージとファイルの構成を考える

| 19:41 | パッケージとファイルの構成を考える - わだばLisperになる を含むブックマーク はてなブックマーク - パッケージとファイルの構成を考える - わだばLisperになる

あるときぼんやりとsb-sequenceを眺めていて、sb-sequenceでは、メソッドが、

(defmethod sequence:count ...)

のように定義されていることをみつけました。

何故、パッケージ付きの名前で定義されているかのは、はっきりとした記述はみつけられず不明ですが、こういう記述方法も特定の状況では便利なのかもしれないと思い、色々考えてみました。

例えば、あまりこういう状況もないかと思いますが、

(defpackage :foo 
  ....
  (:export :foo))

(in-package :foo)

(defun foo (n)
  (foo-bar-baz:frobozz-a
   (foo-bar-baz:frobozz-b n) ))

のように内部シンボルより外部パッケージのシンボルを呼ぶ方が多かったりする場合は、

(in-package :foo-bar-baz)

(defun foo:foo (n)
  (frobozz-a
   (frobozz-b n) ))

のように書いた方が楽といえば楽です。

この辺りをぼんやりと考えていたのですが、この方式を整理してもう少し実用的にならないものかと規約的なものを考えてみました。

  1. 内部用のパッケージを作成し、ごちゃごちゃしたものは全部ここに取り込む(なんならテストも)。名前は、主パッケージ名がfooならば、foo-internalsでnicknameは、fooiなどにしておく。
  2. 主となるパッケージは基本的にuse-packageせずexportするのみ
  3. 定義で使うパッケージは、foo-internals
  4. fooからエクスポートされるものは、foo-internalsの中で、(defun foo:fctn-a (...のようにパッケージ名付きで定義を書く

という感じです。

(require :kmrcl)
(require :fiveam)

(defpackage :foo-internals
  (:use :cl
        :kmrcl
        :fiveam ;テストライブラリ
        )
  (:nicknames :fooi))

(defpackage :foo
  (:export :fctn-a
           :fctn-b
           :fctn-c
           :fctn-d))

(def-suite :foo)

(in-package :fooi)
(in-suite :foo)

(defun foo:fctn-a (n)
  (* n 1))

(test foo:fctn-a
  (is (= (foo:fctn-a 3)
         3)))

(defun fctn-b-1 (n)
  (* n n))

(test fctn-b-1
  (is (= (fctn-b-1 3)
         9)))

(defun foo:fctn-b (n)
  (fctn-b-1 n))

(test fctn-b-1
  (is (= (fctn-b-1 3)
         9)))
...

(run!)
;-> ..
;    Did 2 checks.
;       Pass: 2 (100%)
;       Skip: 0 ( 0%)
;       Fail: 0 ( 0%)
;
;=> NIL

上の例では、テストと実装が一緒になっていますが、CLではパッケージの単位とファイルの単位は無関係なので分けるのもOKだと思います。

先にエクスポートするものが決まっている場合には、この方式は割と有効かなとも思えました。

例えば、他の言語のライブラリ(SRFIの関数など)をCLに移植する場合等は、シンボルの定義/方針を先に決めてしまってから実装する、というのも結構良いかなと思います。

等々、なにかアイデア/問題点等ありましたら教えてください!

ゲスト



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