4

以下のスニペットで何が起こっているのだろうと思っていました。シーケンスの評価を強制せずに関数が適切に再定義されないのはなぜですか?

user> (defn foo [] (map vector (range 3)))
#'user/foo
user> (defn bar [] (map #(vector %) (range 3)))
#'user/bar
user> (foo)
([0] [1] [2])
user> (bar)
([0] [1] [2])
user> (with-redefs [vector (fn [_] "what does the fox say?")] (foo))
("what does the fox say?" "what does the fox say?" "what does the fox say?")
user> (with-redefs [vector (fn [_] "what does the fox say?")] (bar))
([0] [1] [2])
user> (with-redefs [vector (fn [_] "what does the fox say?")] (vec (bar)))
["what does the fox say?" "what does the fox say?" "what does the fox say?"]
user> 

ありがとう!

4

1 に答える 1

6

違いはfoovector, を の引数として呼び出すとmap、 が評価され (この場合は関数オブジェクトに解決されることを意味します)、再度解決する必要がないことです。コードが終了した後でも、同じ関数オブジェクトが使用されますwith-redefs

barただし、 では、それは への引数ではなくvector、名前mapで参照する無名関数です。vectorその結果、無名関数は 1 回だけ評価されvectorますが、無名関数が呼び出されるたびに解決されます。mapは遅延しているため、コードが既に終了した後に発生していwith-redefsます (強制評価時を除く)。

重要な点は、関数呼び出しのように、(map vector (range 3))各引数が評価され、呼び出し元の関数がそれらの評価の結果を取得することです。つまり、 in の呼び出しmapfooredefinedを取得しますが、 inの呼び出しは呼び出されたときに名前で検索する必要がある関数を取得します。vectormapbarvector

Clojure.org の評価ページには、シンボルがオブジェクトに解決される方法に関する詳細が記載されています。これも遅延バインディングの一例です。

于 2013-10-13T04:49:50.183 に答える