私は最近、いくつかの Lisp (Common Lisp) を学ぼうとしていますが、列挙型を介して C でできるように、定数に名前を付ける方法があるかどうか疑問に思っています。
列挙型の完全な機能セットは必要ありません。最終的には、高速で読みやすいコードが必要です。
グローバルと小さな関数を試しましたが、常にパフォーマンスが低下しました。数値をコードに差し込むだけで、常に高速になりました。
私は最近、いくつかの Lisp (Common Lisp) を学ぼうとしていますが、列挙型を介して C でできるように、定数に名前を付ける方法があるかどうか疑問に思っています。
列挙型の完全な機能セットは必要ありません。最終的には、高速で読みやすいコードが必要です。
グローバルと小さな関数を試しましたが、常にパフォーマンスが低下しました。数値をコードに差し込むだけで、常に高速になりました。
Lisp で列挙を行う通常の方法は、シンボルを使用することです。シンボルはインターンされる (シンボル テーブルのエントリへのポインターに置き換えられる) ため、整数と同じくらい高速で、他の言語の列挙型定数と同じくらい読み取り可能です。
したがって、C では次のように記述できます。
列挙型 { りんご、 オレンジ、 バナナ、 };
'apple
Lisp では、 , 'orange
and を'banana
直接使用できます。
列挙型が必要な場合は、次のように定義できますdeftype
。
(deftype フルーツ () '(メンバー アップル オレンジ バナナ))
、などでタイプfruit
を使用できます。declare
typep
typecase
その型に特化したジェネリック関数を書くことができます.
たとえば、フォントサイズに名前を付けたいとします。
(defconstant +large+ 3)
(defconstant +medium+ 2)
(defconstant +small+ 1)
あなたはそれを短くするためにマクロを書くことができます。
上記の定数定義は通常、これらの数値を外部の非Lispコードに渡す必要がある場合にのみ記述されます。
それ以外の場合は、キーワード記号:: large、:medium、および:smallを使用します。
あなたはEQと平等のためのいくつかのテストを使用するすべてでそれらをテストすることができます。
(let ((size :medium))
(ecase size
(:small ...)
(:medium ...)
(:large ...)))
そのためのメソッドを作成することもできます。
(defmethod draw-string (message x y (size (eql :large))) ...)
前述のように、セットタイプを定義できます。
(deftype size () '(member :small :medium :large))
次に、何かがそれらのいずれかであるかどうかを確認できます。
(let ((my-size :medium))
(check-type my-size size))
my-sizeが:small、:medium、または:largeのいずれでもない場合、上記はエラーを示します。
defclass形式でタイプを使用することもできます。
(defclass vehicle ()
((width :type size :initarg :width)))
ここで、次のようなオブジェクトを作成します。
(make-instance 'vehicle :width :large)
一部のCommonLisp実装は、スロットを不正な値に設定したときにチェックします。
クラスVehicleのオブジェクトを作成する場合、スロットは:large、:medium、または:smallのいずれかになります。デバッガー、インスペクター、またはその他のツールでオブジェクトを見ると、1、2、3(または通常使用する値)ではなく、シンボリック名が表示されます。
これはLispスタイルの一部です。可能な場合は記号名を使用してください。外部関数へのインターフェイスコード(列挙型を使用する外部Cコードの呼び出しなど)でのみ数値を持つシンボルを使用します。
列挙型は Lisp では冗長です。その理由は、すべてのシンボルが独自の ID であるためです。したがって、それらをそのまま使用できます。たとえば、次のようになります。
[dsm@localhost:~]$ clisp -q
[1]> (setf x 'some) ;'
SOME
[2]> (eq x 'some) ;'
T
[3]>