编写Clojure#[...]向量函数宏

时间:2017-12-02 13:33:48

标签: function vector clojure macros

我想写一个Clojure向量宏表单#[...]我可以像#[(inc %1) %2](fn [a b] [(inc a) b])那样使用#(vector (inc %1) %2)

这是一个特殊的数据阅读器,还是可以用defmacro编写?

1 个答案:

答案 0 :(得分:1)

只是为了笑,我写了可能是你最接近解决方案的东西。它没有定义一个阅读器宏,但它确实定义了一个几乎允许你正在寻找的语法的宏。

我不得不重新发明轮子以允许%样式隐式参数,因为我无法滥用#()工作:

(defn arg-list
  "Returns a lazy-seq of (%, %2, %3, ...) strings."
  ([] (arg-list 1))
  ([n] (lazy-seq
         (cons (str "%" (if (> n 1) n))
               (arg-list (inc n))))))

(defmacro lambda
  "Use as you would #(). (map (lambda (* % 2)) [1, 2, 3])"
  [& body]
  (let [arg-syms (->> (arg-list) (take 5) (mapv symbol))]
    `(fn [& ~arg-syms]
       ~@body)))

这定义了一个模仿#()阅读器宏的常规宏。它评估为一个可变参数函数,它具有绑定到"百分比"的列表中的前5个参数。符号。它允许%样式参数:

(mapv (lambda (* % %2)) [1 2 3] [1 5 9])
[1 10 27]

然后,您可以使用它来定义几乎完成您正在寻找的宏:

(defmacro vec-f [& elems]
  `(lambda (vec ~(vec elems))))
(mapv (vec-f (inc %) %2) [1 2 3] [1 5 9])
[[2 1] [3 5] [4 9]]

但我不能说我建议使用它。

  • 它不具备可读性。

  • 错过的参数不会抛出ArityException,而是通过解构默认为nil

  • 最多只允许%5;虽然这是一个可以增加的硬编码限制。使用当前" var-arg方法",我不能允许任意数量的参数。试图在编译时实现无限列表显然会以泪流满面。

作为一个概念证明,它显示了你几乎之后的所有内容。

你应该使用

#(vector (inc %1) %2)

相反,或者,正如评论

中所建议的那样
#(do [(inc %1) %2])