clojure macro - 不知道如何从以下位置创建 ISeq:clojure.lang.Symbol



我正在试验clojure宏,想知道我可能做错了什么?

我有一个简单的例子,尝试基于映射动态创建函数。

例如:

(def units {:cm 100
            :mm 1000
            :m  1
            :km 1/1000})
(defn m-to-unit-helper [[k v]]
  (let [f (symbol (str "to-" (name k)))]
    `(defn ~f [m#] (* ~v m#))))
(defmacro m-to-units [units-map]
  (let [funcs (map m-to-unit-helper units-map)]
    `(do ~@funcs)))
; complains with: Don't know how to create ISeq from: clojure.lang.Symbol
(m-to-units units)
; To try and debug
(defn debug [units-map]
  (let [funcs (map m-to-unit-helper units-map)]
    (clojure.pprint/pprint `(do ~@funcs))))
; see below
(debug units)

宏不起作用,但调试输出看起来应该创建正确的结构:

(do
 (clojure.core/defn
  to-mm
  [m__32709__auto__]
  (clojure.core/* 1000 m__32709__auto__))
 (clojure.core/defn
  to-m
  [m__32709__auto__]
  (clojure.core/* 1 m__32709__auto__))
 (clojure.core/defn
  to-cm
  [m__32709__auto__]
  (clojure.core/* 100 m__32709__auto__))
 (clojure.core/defn
  to-km
  [m__32709__auto__]
  (clojure.core/* 1/1000 m__32709__auto__)))

如有任何建议,我们将不胜感激。谢谢

m-to-units是一个宏,这意味着每个参数都将在不进行求值的情况下传递,这意味着您在宏中units-map的值实际上是符号units

现在,如果你直接通过地图,它将按预期工作:

 (m-to-units {:mm 1000, :m 1, :cm 100, :km 1/1000})
 ;; => #'user/to-km
 (to-cm 10)
 ;; => 1000

你可以做的是——尽管我认为这是一种糟糕的做法——使用eval来获得单位映射的实际值,无论它是作为映射还是通过符号传递:

(defmacro m-to-units
  [units-map]
  (let [funcs (map m-to-unit-helper (eval units-map))]
    `(do ~@funcs)))
(m-to-units units)
;; => #'user/to-km

最新更新