19

Clojureでは、

(def x 3)
(eval '(prn x))

3を印刷しますが、

(let [y 3]
   (eval '(prn y)))

(binding [z 3] (eval '(prn z)))

'変数を解決できません'例外を生成します。

http://clojure.org/evaluationによるとeval、、、load-stringなどは、その内容を評価するための一時的な名前空間を生成します。したがって、上記のコードサンプルはどちらも機能しないと思い(def x 3)ます。これは、によって作成された名前空間ではなく、現在の名前空間で行われるためevalです。

  1. 最初のコードサンプルが機能し、最後の2つが機能しないのはなぜですか?
  2. eval使用せずに変数がバインドされたフォームを使用するにはどうすればよいdefですか?

ありがとう!

4

1 に答える 1

16

1.:

これが機能しない理由は、(多かれ少なかれ) リンクしたページに示されています。

It is an error if there is no global var named by the symbol […]

と:

[…]

  1. シンボルから var へのマッピングがあるかどうかを確認するために、現在の名前空間でルックアップが行われます。その場合、値はシンボルによって参照される var のバインディングの値です。

  2. エラーです。

eval空 ( CL-lingo ではnull ) 字句環境でフォームを評価します。これは、呼び出し元のスコープからレキシカル変数バインディングにアクセスできないことを意味します。また、既存の変数の新しいバインディングを作成します。そのため、バインドしようとする変数をd またはed しbindingないと、「単独で」使用することはできません。さらに、レキシカル変数 (少なくとも CL では、Clojure の場合がそうでなかったら驚くだろう) は、実行時に既に存在しなくなりました。それらはアドレスまたは値に変換されます。declaredef

このトピックに関する私の以前の投稿も参照してください。

2.:

したがって、動的変数を使用する必要があります。明示的な を避けることができdefますが、少なくともdeclareそれらが必要です (これdefはバインディングなしの var 名です):

user=> (declare ^:dynamic x)
#'user/x
user=> (binding [x 10] (eval '(prn x)))
10
nil

ところで、なぜ eval が必要なのか、他の解決策が適切な場合にeval を使用するのは悪と見なされることはご存知だと思います。

于 2011-06-03T00:22:36.560 に答える