【问题标题】:Writing a Clojure #[...] Vector Function Macro编写 Clojure #[...] 向量函数宏
【发布时间】:2017-12-02 13:33:48
【问题描述】:

我想写一个 Clojure 向量宏形式 #[...] 我可以像 #[(inc %1) %2] 这样使用,它相当于 (fn [a b] [(inc a) b])#(vector (inc %1) %2)

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

【问题讨论】:

标签: function vector clojure macros


【解决方案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]]

但我不能说我推荐使用它。

  • 它不利于可读性。

  • 没有抛出ArityExceptions,错过的参数将通过解构默认为nil

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

不过,作为概念证明,它表明您所追求的目标是几乎可能的。

你应该只使用

#(vector (inc %1) %2)

相反,或者,如 cmets 中所建议的那样

#(do [(inc %1) %2]) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-23
    • 2023-04-03
    • 2020-05-29
    • 1970-01-01
    • 2011-12-12
    • 2010-11-14
    • 1970-01-01
    • 2011-12-12
    相关资源
    最近更新 更多