1

reading中に(他のアクションの中でも)ハッシュテーブルを作成しようとしています。ハッシュテーブルに(まだ)グローバルスコープを持たせたくないので、マクロとを使用してこれを実行していgensymます。マクロ内で、に似xたマクロを定義していますが、どこかにシンボルを定義する代わりに、ハッシュテーブルのエントリを定義しています。爆破します。エラーメッセージは理解できたと思いますが、どうすれば機能させることができますか?ssetf

コード:

#!/usr/bin/clisp -repl

(defmacro x (&rest statements)
  (let ((config-variables (gensym)))
    `(macrolet ((s (place value)
                  (setf (gethash 'place ,config-variables) value)))
       (let ((,config-variables (make-hash-table :test #'eq)))
         (progn ,@statements)
         ,config-variables))))

(defun load-config ()
  (let ((config-file-tree (read *standard-input*)))
    (eval config-file-tree)))

(defun load-test-config ()
  (with-input-from-string (*standard-input* "(x (s fred 3) (s barney 5))")
    (load-config)))

(load-test-config)

出力:

*** - LET*: variable #:G12655 has no value
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead of #:G12655.
STORE-VALUE    :R2      Input a new value for #:G12655.
SKIP           :R3      skip (LOAD-TEST-CONFIG)
STOP           :R4      stop loading file /u/asterisk/semicolon/build.l/stackoverflow-semi
4

2 に答える 2

4

ビルが本当に欲しいものを推測するだけです。

ファイル内の構成として、いくつかのキーからいくつかの値へのマッピングが必要だとします。

これが手順です。

  • データへのストリームを開きます
  • s式として読む
  • データをウォークし、ハッシュテーブルに入力します

コード例:

(defun read-mapping (&optional (stream *standard-input*))
  (destructuring-bind (type &rest mappings) (read stream)
    (assert (eq type 'mapping))
    (let ((table (make-hash-table)))
      (loop for (key value) in mappings
            do (setf (gethash key table) value))
      table)))

(defun load-config ()
  (read-mapping))

(defun load-test-config ()
  (with-input-from-string (*standard-input* "(mapping (fred 3) (barney 5))")
    (load-config)))

(load-test-config)

使用する:

CL-USER 57 > (load-test-config)
#<EQL Hash Table{2} 402000151B>

CL-USER 58 > (describe *)

#<EQL Hash Table{2} 402000151B> is a HASH-TABLE
BARNEY      5
FRED        3

利点:

  • マクロなし
  • データはソースコードと生成されたソースコードにエンコードされません
  • EVALによる評価(セキュリティ!)は必要ありません
  • より大きなコードに拡張されているマクロを介したオブジェクトコードの膨張はありません
  • 機能的抽象化
  • 理解とデバッグがはるかに簡単

あるいは、ハッシュテーブルとして直接読み取られる{ような読み取りマクロを作成します。{(fred 3) (barney 5)}


計算値が必要な場合:

(defun make-table (mappings &aux (table (make-hash-table)))
  (loop for (key value) in mappings
        do (setf (gethash key table) (eval value)))
  table)

CL-USER 66> (describe (make-table '((fred (- 10 7)) (barney (- 10 5)))))

#<EQL Hash Table{2} 4020000A4B> is a HASH-TABLE
BARNEY      5
FRED        3

それをマクロに変える:

(defmacro defmapping (&body mappings)
  `(make-table ',mappings))

(defmapping
  (fred 3)
  (barney 5))
于 2011-12-25T14:12:08.193 に答える
3

マクロも定義しmacroletているので、通常のルールが適用されます。つまり、実行時に評価される式をバッククォートする必要があります。このような:

(defmacro x (&rest statements)
  (let ((config-variables (gensym)))
    `(macrolet ((s (place value)
                 `(setf (gethash ',place ,',config-variables) ,value)))
      (let ((,config-variables (make-hash-table :test #'eq)))
        (progn ,@statements)
        ,config-variables))))
于 2011-12-25T13:09:44.703 に答える