如何在clojure中创建这个宏可变参数?

Joh*_*den 5 macros clojure

我想做一些叫做ds的东西

(let [a 2]
  (ds a))
Run Code Online (Sandbox Code Playgroud)

- >

 "a->2"
Run Code Online (Sandbox Code Playgroud)

(let [a 1 b 2 c 3]
    (ds a b c)) 
Run Code Online (Sandbox Code Playgroud)

- >

 "a->1, b->2, c->3"
Run Code Online (Sandbox Code Playgroud)

到目前为止,我已经达到了:

(defmacro ds3 [a b c] 
     `(clojure.string/join ", " 
          [(str '~a "->" ~a) 
           (str '~b "->" ~b) 
           (str '~c "->" ~c)]))
Run Code Online (Sandbox Code Playgroud)

这似乎工作:

 (let [ a 1 b 2 c 3]
     (ds3 a b c)) ; "1->1, 2->2, 3->3"
Run Code Online (Sandbox Code Playgroud)

显然我可以定义ds1 ds2 ds3等...但是我想知道如何使它成为可变参数?

Ank*_*kur 10

干得好:

(defmacro ds [& symbols]                                                                                                                             
  `(clojure.string/join ", "                                                                                                                         
                        ~(into [] 
                           (map (fn [s] `(str ~(name s) "->" ~s))  symbols))))                                                                
Run Code Online (Sandbox Code Playgroud)


ama*_*loy 7

Ankur的答案可能是最实用的,但是他将很多工作推迟到运行时,这可以在宏扩展时完成.这是一个非常有用的练习,可以很好地演示功能宏,看看你在编译时可以做多少工作:

(defmacro ds [& args]
  `(str ~(str (name (first args)) "->")
        ~(first args)
        ~@(for [arg (rest args)
                clause [(str ", " (name arg) "->") arg]]
            clause)))

(macroexpand-1 '(ds a b c))
=> (clojure.core/str "a->" a ", b->" b ", c->" c)
Run Code Online (Sandbox Code Playgroud)

这样可以避免在运行时构建任何临时对象,并且可以实现绝对最少的字符串连接数.