5

setf特定の変数に応じて、構造体のさまざまなフィールドを作成したいと思います。次のアプローチを使用することにしました。

フィールドのアクセサー名で文字列を生成します。

(setq my-string (format nil "STRUCT-ESTADISTICAS-NUM-~S" x))

次に、funcall でインターンを使用します。

(funcall (intern my-string) *estadisticas*)

この呼び出しは構造体のフィールドの正しい値を返しますが、setfこの値を変更しようとすると、次のように不平を言います:

(setf (funcall(intern my-string) *estadisticas*) 0)
Error: `(SETF FUNCALL)' is not fbound

機能しない理由は理解できますが、構造体のフィールドを変更する方法が見つかりません。何か案が?ありがとうございました。

4

2 に答える 2

5

動機:

構造物は比較的低レベルの施設です。「スピード」は重要な設計目標でした。ライター関数を介した間接参照は、標準ではサポートされていません(私が読んだように)。現在、構造の効率を高める必要がない限り、デフォルトとしてCLOSを使用してください(構造を使用したスロットの読み取りと書き込みを高速化できる場合があります)。

最初のスタイル:

INTERNは使用せず、FIND-SYMBOLを使用してください。パッケージも指定します。指定しない場合、FIND-SYMBOLは*package*のランタイム値をパッケージとして使用します。

2番目-DEFSTRUCT

ANSI CL規格を正しく読んだ場合、DEFSTRUCTがDEFCLASSのようにスロットのライター関数を作成するわけではありません。

CL-USER 24 > (defstruct foo bar baz)
FOO

CL-USER 25 > #'(setf foo-bar)

Error: Undefined function (SETF FOO-BAR) in form (FUNCTION (SETF FOO-BAR)).

したがって、DEFSTRUCTで定義されたそのような関数がないため、そのような名前(SETF FOO-BAR)を作成し、その関数を見つけようとすると失敗します。

ユーザーコード(setf(foo-bar some-struct)42)で機能するものは、DEFSTRUCTによって提供される定義済みのSETF拡張に基づいていますが、定義済みのSETFアクセサー関数には基づいていません。

一部のCommonLisp実装は、ANSICLの非標準拡張としてライター関数を提供する場合があります。

考えられる解決策

a)CLOSクラスを使用すると、DEFCLASSは必要な処理を実行します

b)ライター関数を自分で作成する

(defun (setf foo-bar) (new-value struct)
   (setf (foo-bar struct) new-value))

今:

(funcall (fdefinition '(setf foo-bar)) 300 *foo*)

上記はその後動作します。

c)(SETF SLOT-VALUE)-一部の実装のもう1つの非標準機能。

Common Lispの一部の実装では、これはCLOSクラスだけでなく、構造体でも機能します。

(setf (slot-value some-struct 'bar) 42)

Allegro CLがそれをサポートしているかどうかはわかりませんが、それは簡単にわかります。

于 2010-09-07T07:16:57.957 に答える
5

名前を介して構造体のライター関数を呼び出したいとします。ライターの名前は list(setf accessor-name)です。それで

(funcall (fdefinition (list 'setf (intern my-string))) 0 estadisticas)

編集:

コードの残りの部分が表示されないため、何が問題なのかを理解するのは困難です。SBCLでは、これは私にとってはうまくいきます:

(defstruct point x y)
(let ((point (make-point :x 1 :y 2)))
  (funcall (fdefinition (list 'setf (intern "POINT-X"))) 10 point)
  point)

上記は次のように評価されます

#S(POINT :X 10 :Y 2),

予想通り。

于 2010-09-04T10:57:31.097 に答える