在使用params的clojure宏中使用匿名函数

mah*_*ang 0 macros clojure

mydata是关于使用的名称和性别:

(def mydata [["a" 'f] ["b" 'm]])
Run Code Online (Sandbox Code Playgroud)

我想要的是:

(group-by #(let [[name gender] %1] name) mydata)
; {"a" [["a" f]], "b" [["b" m]]}
Run Code Online (Sandbox Code Playgroud)

并且:

(group-by #(let [[name gender] %1] gender) mydata)
; {f [["a" f]], m [["b" m]]}
Run Code Online (Sandbox Code Playgroud)

所以我想构建一个这样的函数:

(defn my-group-by [data, field]
  (group-by #(let [[name gender] %1] field) mydata))
Run Code Online (Sandbox Code Playgroud)

但它出错了

(mygroup-by mydata 'name)
; {name [["a" :F] ["b" :M]]}
Run Code Online (Sandbox Code Playgroud)

然后我认为宏可以做到这一点

(defmacro my-macro [data field]
  `(group-by #(let [[name,gender] %1] ~field) ~data))
Run Code Online (Sandbox Code Playgroud)

然后我跑了

(my-macro mydata name)
; CompilerException java.lang.RuntimeException: Can't let qualified name: clojure.core/name, compiling:(/tmp/form-init2648255959159095748.clj:1:1) 
Run Code Online (Sandbox Code Playgroud)

为什么?哪里错了?

Thu*_*ail 6

没有必要为此使用宏.

如果您将数据表示为一系列地图:

(def mydata [{:name "a", :gender :F}
             {:name "b", :gender :M}
             {:name "a", :gender :M}]) ; extra line
Run Code Online (Sandbox Code Playgroud)

...然后你可以使用地图的关键字作为功能:

(group-by :gender mydata)
{:F [{:gender :F, :name "a"}],
 :M [{:gender :M, :name "b"} {:gender :M, :name "a"}]}
Run Code Online (Sandbox Code Playgroud)

(group-by :name mydata)
{"a" [{:gender :F, :name "a"} {:gender :M, :name "a"}],
 "b" [{:gender :M, :name "b"}]}
Run Code Online (Sandbox Code Playgroud)

如果地图证明太慢,您可以将它们变成记录:

(defrecord user [name gender])

(def mydata [(map->user {:name "a", :gender :F})
             (map->user {:name "b", :gender :M})
             (map->user {:name "a", :gender :M})])
Run Code Online (Sandbox Code Playgroud)

......像地图那样工作.