Несоответствия при попытке переопределить функции в Clojure - PullRequest
2 голосов
/ 31 октября 2019

Я играю с Clojure with-redefs-fn, и я вижу некоторые загадочные несоответствия. Например:

(with-redefs-fn {#'println (constantly nil)} #(println "foo"))
=> nil

Как и ожидалось, println больше не имеет никакого эффекта, просто увеличивается до nil. Однако в:

(with-redefs-fn {#'= (constantly false)} #(= 1 1))
=> true

(with-redefs-fn {#'+ (constantly 0)} #(+ 1 1))
=> 2

(with-redefs-fn {#'max (constantly 1)} #(max 1 2))
=> 2

Мы больше не видим ожидаемое поведение, функции переопределения, кажется, работают как обычно. Я подозреваю, что эти конкретные простые функции оптимизированы для операций с байт-кодом и, таким образом, не зависят от переопределения. Может кто-нибудь подтвердить это, потому что это меня некоторое время озадачивает.

Интересно, что если вы обращаетесь к var, но не в позиции вызова функции, вы получите переопределенное значение:

user=> (with-redefs-fn {#'= (constantly false)} #(constantly =))
#object[clojure.core$constantly$fn__5672 0x72458efc "clojure.core$constantly$fn__5672@72458efc"]
user=> =
#object[clojure.core$_EQ_ 0x2caf6912 "clojure.core$_EQ_@2caf6912"]

Ответы [ 2 ]

0 голосов
/ 31 октября 2019

Это связано с встраиванием:

(defn not-inlined [arg]
  (println "Won't be inlined"))

(defn inlined
  {:inline (fn [a] `(println "Was inlined!" ~a))}
  [arg]
  (println "Wasn't inlined!"))


(with-redefs-fn {#'not-inlined (constantly "REDEFINED!")}
  #(println (not-inlined 1)))
=> REDEFINED!

(with-redefs-fn {#'inlined (constantly "REDEFINED!")}
  #(println (inlined 1)))
=> Was inlined! 1

println не встроено, в то время как =, + и max. Я не полностью уверен, как работает встраивание, но если вся функция буквально заменяется предоставленным телом, inlined не будет существовать для переопределения.

0 голосов
/ 31 октября 2019

Интересно, что если вы обращаетесь к var, но не в позиции вызова функции, вы получаете переопределенное значение:

user=> (with-redefs-fn {#'= (constantly false)} #(constantly =)) 
#object[clojure.core$constantly$fn__5672 0x72458efc"clojure.core$constantly$fn__5672@72458efc"]
user=> =
#object[clojure.core$_EQ_ 0x2caf6912 "clojure.core$_EQ_@2caf6912"

, что определенно не делает проблему «длины списка аргументов». Определенно похоже на какую-то оптимизацию встраивания.

Да, встраивание: https://github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/core.clj#L976

user=> (with-redefs-fn {#'compare (constantly false)} #(compare 0 1))
-1

https://github.com/clojure/clojure/blob/clojure-1.9.0/src/clj/clojure/core.clj#L830

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...