Clojure シンボルの説明 質問する

Clojure シンボルの説明 質問する

"a"関数にバインドされたシンボルがあります:

(defn a []
    (println "Hello, World"))

user=> a
#<user$a__292 user$a__292@97eded>
user=> (a)    
Hello, World
nil

次に、syntax-quoteを使用します。これは、「現在のコンテキストでシンボルを解決し、完全修飾シンボルを生成します」と、Clojure ドキュメントしかし、なぜ非修飾記号と同じように使用できないのでしょうか?

user=> `a
user/a
user=> (`a)
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)

2 番目の質問: リスト内にシンボルがある場合、シンボルを直接評価する場合と同じ方法で評価できないのはなぜですか?

user=> (def l '(a 1 2))
#'user/l
user=> 'l
l
user=> (first l)
a
user=> ((first l))
java.lang.IllegalArgumentException: Wrong number of args passed to: Symbol (NO_SOURCE_FILE:0)

ここでのシンボルの動作に関する基本的な理解のどこかに致命的な欠陥があるのではないかと疑っています。上記のコードのどこが間違っているのでしょうか?

ベストアンサー1

REPL = 読み取り評価印刷ループ。読み取り評価プロセスをステップ実行します。

読み取り: Clojure は文字列を見て"(`a)"解析し、データ構造を生成します。読み取り時には、リーダー マクロが展開され、それ以外は何も起こりません。この場合、リーダーはバッククォートを展開し、次のようになります。

user> (read-string "(`a)")
((quote user/a))

EVAL: Clojure はこのオブジェクトを評価しようとします。評価ルールは、見ているオブジェクトの種類によって異なります。

  • 一部のオブジェクトは、それ自体として評価されます (数値、文字列、キーワードなど)。
  • シンボルは、何らかの名前空間で解決されて何らかの値を取得することによって評価されます (通常は)。
  • リストは、マクロがなくなるまでリストをマクロ展開し、リストの最初の項目を再帰的に評価して、結果の値、その後、価値リストの最初の項目の値に基づいて、何をするかを決定します。最初の値が特別な形式である場合、特別な処理が行われます。それ以外の場合、最初の値は関数として扱われ、リストの残りの値 (リストのすべての項目を再帰的に評価することによって取得) をパラメーターとして呼び出されます。

clojure.lang.Compiler/analyzeSeqリストまたはシンボルの評価ルールを確認するには、Clojure ソースのを参照してくださいclojure.lang.Compiler/analyzeSymbol。そこには、他の評価ルールが多数あります。

次のようにするとします:

user> (user/a)

REPL は最終的に内部的にこれを実行します:

user> (eval '(user/a))

Clojure はリストを評価していることを認識するため、リスト内のすべての項目を評価します。最初の (そして唯一の) 項目:

user> (eval 'user/a)
#<user$a__1811 user$a__1811@82c23d>

aは特別な形式ではなく、このリストはマクロ展開する必要がないため、シンボルaは名前空間で検索されuser結果の値ここに がありますfn。これは とfn呼ばれます。

あなたのコード

しかし、代わりに次のようになります:

user> (eval '((quote user/a)))

Clojure はリスト内の最初の項目を評価します。リスト自体もリストです。

user> (eval '(quote user/a))
user/a

このサブリストの最初の項目 を評価しました。quoteこれは特殊な形式であるため、特別なルールが適用され、その引数 (シンボルa) は評価されずに返されます。

シンボルa価値この場合、 はfn上記の値でした。そのため、Clojure は Symbol 自体を関数として扱い、呼び出します。Clojure では、Ifnインターフェースを実装するものはすべて のように呼び出し可能ですfn。たまたまclojure.lang.Symbolは を実装していますIfn。関数として呼び出された Symbol は、1 つのパラメーター、コレクションを想定しており、そのコレクション内で自身を検索します。これは次のように使用されることを意図しています。

user> ('a {'a :foo})
:foo

これがここで実行しようとしていることです。ただし、パラメータを渡していないため、「渡された引数の数が間違っています: Symbol」というエラーが発生します (コレクションが必要です)。

コードが機能するには、 が 2 レベル必要ですeval。これは機能します。理由がわかると思います。

user> (eval '((eval (quote user/a))))
Hello, world
user> ((eval (first l)))
Hello, world

実際のコードでは、eval直接使用するのは通常、非常に悪い考えであることに注意してください。マクロの方がはるかに良い考えです。ここではデモのためにのみ使用しています。

Compiler.javaClojure ソースを見て、これがどのように実行されるかを確認してください。理解するのはそれほど難しくありません。

おすすめ記事