質問

Common Lispの変数にバインドされたs-expressionがあります:

(defvar x '(+ a 2))

次に、呼び出されたときに、定義されたスコープ内の式を評価する関数を作成します。私はこれを試しました:

(let ((a 4))
  (lambda () (eval x)))

and

(let ((a 4))
  (eval `(lambda () ,x)))

しかし、これらは両方とも問題を引き起こします。EVALはトップレベルでコードを評価するため、式に含まれる変数をキャプチャできません。 EVALにLETフォームを配置できないことに注意してください。解決策はありますか?

編集:それでは、EVAL問題の解決策がない場合、他にどのように行うことができますか?

編集:正確に私がやろうとしていることについて質問がありました。コンパイラを書いています。式が定義されているレキシカル環境で閉じられた変数を持つs式を受け入れたい。実際、マクロとして記述する方が良い場合があります。

役に立ちましたか?

解決

必要なバインディングを持つコードを作成する必要があります。コードをLETでラップし、コードで使用できるようにするすべての変数をバインドします。

(defvar *x* '(+ a 2))

(let ((a 4))
  (eval `(let ((a ,a))
           ,*x*)))

他のヒント

CLISPは、レキシカル環境でフォームを評価する拡張機能を実装します。拡張機能であるという事実から、標準に準拠した方法でそれを行うことはできないと思います。

(ext:eval-env x (ext:the-environment))

http://clisp.cons.org/impnotes.html#eval-を参照してください。環境

実際に解決したい問題は何ですか?おそらく、あなたはそれを間違った方法で取り組もうとしています。字句バインディングは、スコープ内で字句的に表示されるもの用であり、外部から取得したランダムなもの用ではありません。

動的な閉鎖が必要な場合がありますか?このようなことはCommon Lispには存在しませんが、いくつかのLisp方言(私が理解している限りではPico Lispなど)にはあります。

次の操作をできることに注意してください。これは似ています:

(defvar *a*)
(defvar *x* '(+ *a* 2))  ;'

(let ((a 10))
  ;; ...
  (let ((*a* a))
    (eval *x*)))

ただし、本当にこれが必要かどうかをよく考えることをお勧めします。

COMPILEを使用して式を関数にコンパイルし、PROGVを使用して、変数が動的に設定される環境でコンパイルされた関数をFUNCALLすることができます。または、COMPILEを使用して、式を変数を受け入れる関数にコンパイルすることをお勧めします。

Compileは関数定義をリストとして受け入れ、関数に変換します。 SBCLの場合、この関数はマシンコードにコンパイルされ、効率的に実行されます。

最初のオプション(コンパイルとprogvを使用):

(defvar *fn* (compile nil '(lambda () (+ a 2)))
(progv '(a) '(4) (funcall *fn*))
=>
6

2番目のオプション:

(defvar *fn* (compile nil '(lambda (a) (+ a 2))))
(funcall *fn* 4)
=>
6
scroll top