Как расширить и переопределить макрос clojure? - PullRequest
0 голосов
/ 20 декабря 2018

Я хочу расширить и переопределить макрос clojure.core.Например, как я могу переопределить clojure.core/defn при использовании исходного определения?

1 Ответ

0 голосов
/ 20 декабря 2018

Это немного сложно, но с помощью псевдонима макроса в clojure.core это возможно.

Откройте репл и следуйте приведенным ниже инструкциям.

➜  ~ clj
Clojure 1.9.0

Первый псевдоним clojure.core/defn к чему-то другому:

user=> (in-ns 'clojure.core)
#object[clojure.lang.Namespace 0x48e92c5c "clojure.core"]
clojure.core=> (defmacro defn-holder [])
#'clojure.core/defn-holder
clojure.core=>  (alter-var-root #'defn-holder (constantly (var-get #'defn)))
#object[clojure.core$defn__5154 0xd3957fe "clojure.core$defn__5154@d3957fe"]

Затем создайте новый макрос defn, который использует определение псевдонима

clojure.core=> (in-ns 'user)
#object[clojure.lang.Namespace 0x64ba3208 "user"]
user=> (defmacro defn [& args] `(do (println "aliased version")(clojure.core/defn-holder ~@args)))
WARNING: defn already refers to: #'clojure.core/defn in namespace: user, being replaced by: #'user/defn
#'user/defn
user=> (defn foo [a])
aliased version
#'user/foo
user=> (foo 1)
nil

Однако он пока не работает для всех пространств имен:

user=> (ns bar)
nil
bar=> (defn foo [a])
#'bar/foo

Нам нужно переопределить defn в clojure.core с нашим новым определением:

bar=> (in-ns 'clojure.core)
#object[clojure.lang.Namespace 0x48e92c5c "clojure.core"]
clojure.core=> (alter-var-root #'defn (constantly (var-get #'user/defn)))
#object[user$defn 0x37052337 "user$defn@37052337"]

Теперь это работает:

clojure.core=> (in-ns 'bar)
#object[clojure.lang.Namespace 0x37efd131 "bar"]
bar=> (defn foo [a])
aliased version
#'bar/foo
...