2013-07-09 8 views
5

私は、私が欲しいと知っているいくつかのプロパティと、基本構造には必要ない他のプロパティの任意の数を持つ構造体を定義しようとしています。任意の数のargsでlispの構造を定義するには?

(defstruct (node (:type list)) label [other args here]) 

は、私はあなたが行うことができます関数の中で知っている:

(defun foo (arg1 &rest args) ...) 

defstructの等価&restのいくつかの並べ替えがありますか?

私はちょうどlispを学んでいるので、私は何かが欠けていると感じています。 &restに相当するものがない場合、私はこれについてどのように考えているのでしょうか?前もって感謝します!

答えて

6

あなたが探しているものは正確ではありません。構造体のデフォルトの場合は、固定数のスロットを持つレコード型です。各スロットには名前があり、defstructマクロによって生成された関数を通じてアクセスできます。あなたは

(defstruct node 
    label) 

をやった後、例えば、あなたはnode-labelnodeのラベルにアクセスし、高速な検索時間を得ることができます(これは通常、メモリチャンクにだけインデックスだから)。これで、構造体の実装としてリストを使用することができます。この場合、node-labelcarまたはfirstの別名に過ぎません。

(defstruct (node (:type list)) 
    label) 

CL-USER> (make-node :label 'some-label) 
(SOME-LABEL) 
CL-USER> (node-label (make-node :label 'some-label)) 
SOME-LABEL 
CL-USER> (first (make-node :label 'some-label)) 
SOME-LABEL 
CL-USER> (car (make-node :label 'some-label)) 

あなたは、任意のリストベースのキーと値のペアを探しているなら、あなたはおそらく、Common Lispのは、いくつかの便利な機能が含まれているproperty listを、したいです。

プロパティリストも含む構造体を使用する場合は、特別なコンストラクタを追加してそのリストを作成することができます。例えば、Common Lispでは

(defstruct (node (:type list) 
       (:constructor make-node (label &rest plist))) 
    label 
    plist) 

CL-USER> (make-node 'some-label :one 1 :two 2) 
(SOME-LABEL (:ONE 1 :TWO 2)) 
CL-USER> (node-plist (make-node 'some-label :one 1 :two 2)) 
(:ONE 1 :TWO 2) 
+0

ありがとうございます、これはほとんど私が探しているものです。しかし、あなたが置いたように、プロパティリストを 'node'の他のスロットとして持つ方法はありますか?言い換えれば、 '(SOME-LABEL :(1つの1:2)==(SOME-LABEL:ONE 1:TWO 2)'の代わりに ' ONE 1:TWO 2)) '? –

+1

要するに、いいえ。 [Rainerの答え](http://stackoverflow.com/a/17556349/1281433)では、一般的な構造についてより深く掘り下げていますが、構造は固定数のスロットを持つ点が重要です。 '(:type list)'オプションで 'defstruct'を使って" poor man's records "を作成することはできますが、まだ固定数のスロットしか持たないでしょう(つまり、リストは固定数要素)。本当にあなたはプロパティリストがほしいと思うように思えます。 –

+0

ええ、Rainerの答えを読んで、私はそれが私がやっていることに必要な以上の火力だと思う。助けてくれてありがとう、みんな! –

7

は、構造物は、剛性と低レベルのレコードとして考えられています。彼らは派手な動的機能を持っていません。

構造でできることは、別の構造タイプを継承する新しい構造タイプを定義することです。利用できる単一の継承があります。

動的拡張性を処理するには、プロパティリストスロットを構造体に追加するのが一般的です。ジョシュアの答えを見てください。

次に、複数の継承を提供するCommon Lisp Object Systemがあり、実行時にクラスを変更することができます。したがって、クラスにスロットを追加すると、そのクラスのインスタンスが自動的に更新されます。オブジェクトのクラスを変更することもできます。スロットは追加または削除される可能性があります。それでも、通常、クラスのすべてのインスタンスは同じスロットセットを持ちます。ここでも、プロパティリストを持つスロットを追加して拡張性のために使用することができます。

Common Lispには、インスタンスベースごとにスロットを簡単に追加できるオブジェクトシステムがあります。しかし、それはかなり強力ですので、通常はそれを使うだけでは大変です。

CLOSとメタオブジェクトプロトコルを使用すると、非表示にすることができます。ここで私はLispWorksを使用しています:

私達は私達の性質のためのミックスインクラスを定義します。

(defclass property-mixin() 
    ((plist :initform nil)) 
    #+lispworks 
    (:optimize-slot-access nil)) 

設定とプロパティを読み:

(defmethod set-property ((object property-mixin) key value) 
    (setf (getf (slot-value object 'plist) key) value)) 

(defmethod get-property ((object property-mixin) key) 
    (getf (slot-value object 'plist) key)) 

は、今、私たちはSLOT-VALUE受け入れて私たちのプロパティ名を作成する方法を書きます:

(defmethod (setf clos:slot-value-using-class) 
     (value (class standard-class) (object property-mixin) slot-name) 
    (declare (ignorable class)) 
    (if (slot-exists-p object slot-name) 
     (call-next-method) 
    (progn 
     (set-property object slot-name value) 
     value))) 

(defmethod clos:slot-value-using-class ((class standard-class) 
             (object property-mixin) 
             slot-name) 
    (declare (ignorable class)) 
    (if (slot-exists-p object slot-name) 
     (call-next-method) 
    (get-property object slot-name))) 

例。

(defclass automobile (property-mixin) 
    ((company :initarg :company) 
    (motor :initarg :motor)) 
    #+lispworks 
    (:optimize-slot-access nil)) 

今インスタンス:我々は2つのスロットに自動車のクラスを定義

CL-USER 45 > (setf a6 (make-instance 'automobile :company :audi :motor :v6)) 
#<AUTOMOBILE 402005B47B> 

私たちは、通常のスロット値を得ることができますのはないスロットに書いてみましょう

CL-USER 46 > (slot-value c1 'motor) 
:V6 

を存在しますが、プロパティリストに追加されます:

CL-USER 47 > (setf (slot-value a6 'seats) 4) 
4 

我々は戻って値を取得することができます

いくつかの回、あなたが構造や必要だと思うとき:

CL-USER 48 > (slot-value c1 'seats) 
4 
1

を、私は、これは別の回答ではなく、その後のコメントは、とてもここに価値があるだろうと思いましたこれらのエンティティが満たしていないいくつかの特別な要件があります。おそらくこれは、実際に必要なものが異なるデータ構造であるためです。オブジェクトや構造体は、いくつかの条件が満たされたときに有効です。そのような条件の1つは、スロットが静的に認識されていることです。これにより、コンパイラは最適化とエラー報告に適したコードについてより良い理由を示します。

一方、データ構造があります。言語標準ライブラリに付属しているものもあれば、その上に追加されたものもあります。ここには多くのものを提供する1つの図書館があります:http://cliki.net/cl-containersがありますが、特別な場合にはさらに多くのものがあります。

ここでは、リスト、配列、ある種のツリーなどの構造を使用すると、動的にスロットを追加できるようにオブジェクトや構造体を拡張しようとする方がよいと主張します。これは、通常、スロットにアクセスする時間が無視できると予想するためです。それはO(1)と期待しています。これは、オブジェクトが持つスロットの数に関係なく通常発生します。今、あなたが同じセマンティクスを保っている間、あなたはO(n)を作っている下のリストを使用しているとき!もちろん、ハッシュテーブルを使用してO(1)にすることもできます(これは一般的にはスロットアクセスの方が一般的に遅くなります)が、スロットがない場合はnilなどの予期しない動作が発生します通常のエラーの代わりに存在します。

このような方法でオブジェクトを拡張することはCLの一般的な方法ではないと私は考えていますが、これはおそらく他の応答があなたにそれをさせない理由ではありません。私は他の回答者よりCLが少ないと知っていますが、この種の操作を別の言葉で悲しんでいます。これは一般的で、通常は推奨されません。

関連する問題