2012-04-17 65 views
2

我有一个从clojure-csv输出的序列序列。写Clojure宏来生成映射表格

(def s1 [[:000-00-0000 "SMITH" "JOHN" 27][:000-00-0001 "FARMER" "FANNY" 28]]) 

我有一个向量列数[0 3],我想用它来从每个序列中提取数据。

与其写一个函数来将可变数量的地图表单压缩在一起,我认为一个宏可能会诀窍。但是,我有麻烦。

这个宏接受一个序列和列“面具”

(defmacro map-cols [seq & columns] 
    (for [col# columns 
     :let [mc# `(map #(nth % ~col# nil) ~seq)]] 
     mc#)) 

(map-cols s1 cols) 
ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn bene-csv.core/eval2168 

我希望产生在 出现多个映射形式如下:

(zipmap (map #(nth % 0 nil) s1) (map #(nth % 1 nil) s1)) 
{:000-00-0001 "FARMER", :000-00-0000 "SMITH"} 

我希望得到一些我做错了什么想法。当然,我可以根据需要提取的列数调整函数。

谢谢。

编辑:

改性宏

(defmacro map-cols [seq & columns] 
    (vec (for [col columns 
     :let [mc `(map #(nth % ~col nil) ~seq)]] 
     mc))) 


(apply zipmap (map-cols s1 cols)) 

ArityException Wrong number of args (1) passed to: core$zipmap clojure.lang.AFn.throwArity 

回答

4

你混合起来的代码,将在与代码宏将输出宏扩展执行。在你输入一个语法引用之前,你不需要使用auto-gensym(在你的例子中是col#,mc#)。至于宏观产出,它必须始终产生一种形式。看起来你期望它能够生成多种表格(每个表格都有一个表格),但这并不是如何工作的。您的宏输出目前看起来像

((map #(nth % 0 nil) s1) (map #(nth % 1 nil) s1)) 

这是一个包含两个成员的表单。头部位置的成员应该是一个函数,整个表单应该被视为一个函数调用。

解决此问题的方法是将您的forvec一起包含在宏中,然后使用(apply zipmap (map-cols s1 cols))

,回答你的眼前问题,但解决方法将没有任何意义:zipmap想正好有两个参数,因为你说你想要的,输出是一个地图,而不是一个序列拉链在一起他们的而不是一个变量数你的领域。使用(map vector seq1 seq2 ...)来实现拉链。

+0

我不太确定你想让我做什么编辑,所以我编辑了原始问题和输出。谢谢。 – octopusgrabbus 2012-04-17 13:57:50

+0

风格评论:你的:让[mc ...]是多余的。直接产生结果:(对于[col列]'(map#(nth%〜col nil)〜seq)))。至于你的新问题,正如我所说的,zipmap期待着两个参数。就目前来看,你只给出一个,因为你只用一列调用你的宏。 – 2012-04-17 14:02:34

+0

对不起,我无法编译更改。(defmacro map-cols [seq&columns] (vec(for [col columns '(map#(nth%〜col nil)〜seq)]))) – octopusgrabbus 2012-04-17 14:17:44