【问题标题】:clojure macro - don't know how to create ISeq from: clojure.lang.Symbolclojure 宏 - 不知道如何从以下位置创建 ISeq:clojure.lang.Symbol
【发布时间】:2014-10-31 23:24:14
【问题描述】:

我正在试验 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__)))

任何建议将不胜感激。谢谢。

【问题讨论】:

    标签: macros clojure


    【解决方案1】:

    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
    

    【讨论】:

    • 我意识到我来晚了,但更好的做法是什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 2013-12-01
    • 2015-07-29
    • 2011-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多