【问题标题】:Writing Clojure Macro To Generate map Forms编写 Clojure 宏来生成地图表单
【发布时间】:2012-04-17 13:34:53
【问题描述】:

我有一个序列序列,从 clojure-csv 输出。

(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"}

我会很感激我做错了什么。当然,我可以根据需要提取的列数来定制 a 函数。

谢谢。

编辑:

修改宏

(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

【问题讨论】:

    标签: clojure


    【解决方案1】:

    您将在宏扩展时执行的代码与宏将输出的代码混为一谈。在您输入语法引用之前,您不需要使用 auto-gensym(在您的示例中为 col#、mc#)。至于宏输出,它必须始终只产生一种形式。似乎您期望它产生几种形式(每个列一个),但这不是它的工作方式。您的宏输出当前看起来像

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

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

    解决这个问题的方法是使用vecfor 包装在宏中,然后使用(apply zipmap (map-cols s1 cols))

    这回答了您的直接问题,但解决方案仍然没有意义:zipmap 只需要两个参数,而不是您所说的可变数量的参数,并且输出是地图,而不是压缩的序列一起你的领域。使用(map vector seq1 seq2 ...) 实现压缩。

    【讨论】:

    • 我不太确定您希望我进行哪些编辑,所以我编辑了原始问题和输出。谢谢。
    • 风格备注:你的 :let [mc ...] 是多余的。直接生成结果:(for [col columns] `(map #(nth % ~col nil) ~seq))。至于你的新问题,正如我所说, zipmap 需要两个参数。你现在只给它一个,因为你只用一列调用你的宏。
    • 抱歉,我无法编译更改。(defmacro map-cols [seq & columns] (vec (for [col columns `(map #(nth % ~col nil) ~seq)] )))
    • 你把右括号放错了(它应该在列之后)。和我的比较一下。
    猜你喜欢
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 2011-12-12
    • 1970-01-01
    • 2018-05-23
    • 2018-11-21
    • 1970-01-01
    相关资源
    最近更新 更多