我想写一个Clojure向量宏表单#[...]
我可以像#[(inc %1) %2]
或(fn [a b] [(inc a) b])
那样使用#(vector (inc %1) %2)
。
这是一个特殊的数据阅读器,还是可以用defmacro
编写?
答案 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])