2013-10-13 5 views
4

Мне было интересно, что происходит в фрагменте ниже. Почему функция не переопределена, не заставляя оценивать последовательность?с-redefs на функции, используемые внутри карт

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> 

Спасибо!

ответ

6

Разница заключается в том, что при вызове foo, vector, в качестве аргумента map, оценивается (в данном случае означает, что его разрешение на объект функции) один раз и не должна быть решено еще раз. Этот же функциональный объект используется даже после выхода вашего кода with-redefs.

В bar, однако, это не vector, что аргумент, чтобы map, но вместо того, чтобы анонимная функция, которая ссылается на vector по имени. В результате, когда анонимная функция оценивается только один раз, vector будет разрешаться каждый раз при вызове анонимной функции. Потому что map ленив, это происходит после того, как код уже вышел with-redefs (за исключением случаев, когда ваша оценка силы).

Ключевым моментом является то, что в вызове функции - как (map vector (range 3)) - каждый аргумент оценивается, и вызывающая функция получает результат этих оценок. Это означает, что вызов map в foo получает переопределенную vector, тогда как вызов map в bar получает функцию, которая по-прежнему должна искать vector по имени при вызове.

В Clojure.org page on evaluation приведены некоторые сведения о том, как символы разрешены объектами. Это также пример late binding.

Смежные вопросы