【问题标题】:Clojure : Defining a forv macro using forClojure:使用 for 定义一个 forv 宏
【发布时间】:2016-09-06 15:15:53
【问题描述】:

我正在尝试编写我的第二个宏,但我完全被困在这里。

我想避免每次都写(vec (for [...])),所以我尝试写一个forv 宏,比如filterv、mapv 等。 我在我的程序中主要使用向量,因为我需要访问索引,因为我使用外部缓冲区/描述符来固定矩阵过程。 我写了很多类似 ***v 的函数(还有像 fmap 这样的自适应函数),但我坚持使用。

所以我写了

(defmacro forv
  [seq-exprs body-expr]
  (vec (for (vec seq-exprs) body-expr)))

我尝试单独使用 seq-exprs,但它不起作用。老实说,我也尝试过~等等,但我不知道它是如何工作的,我在我的第一个宏中成功了,因为它要容易得多。

Clojure 告诉我 for 需要一个用于绑定的向量。

有人可以帮助我并解释我缺少什么吗?谢谢!

【问题讨论】:

  • 您能否详细说明一下为什么需要将for 返回值显式转换为向量?
  • 我添加了解释。一般是我经常需要访问索引或通过索引来访问算法。
  • @nha's answer 传递了@AlanThompson's 检测到的一些病态调用。例如,给定(forv '() 888),前者返回[],而后者检测到错误。

标签: clojure macros


【解决方案1】:

您可以使用内置的into the Tupelo Library。源码在这里:https://github.com/cloojure/tupelo/blob/master/src/tupelo/core.cljc#L181

(defmacro forv
  "Like clojure.core/for but returns results in a vector.  Equivalent to (into [] (for ...)). Not
   lazy."
  [& body]
  `(vec (for ~@body)))

【讨论】:

  • 也谢谢,其他的好像没什么不同,所以我选择了第一个发布的!
  • 是的,但我的更简单。 ;)
【解决方案2】:
;;
;; you want something like that in the end: (forv [x (range 2)] x)  => (vec (for [x (range 2)] x))
;;

(defmacro forv
  [seq-exprs body-expr]
  `(vec (for [~@seq-exprs] ~body-expr)))
;;
;; check quote and unquote
;; in particular, check the tricky bit is https://clojuredocs.org/clojure.core/unquote-splicing
;;

编辑:我的回答基于模仿问题中的原始代码,但 Alan 的回答比我的要好。

【讨论】:

  • 谢谢。 ~@ 和 ~ 有什么区别?我没有找到任何解释。我还看到我需要报价,谢谢。
  • 尝试在 REPL 中使用这两种形式来获得差异,但在你的情况下,想想你会以seq-exprs 传递什么。这将是一个清单。你不想要这个:[(x 1 y 2)],而是这个:[x 1 y 2]
猜你喜欢
  • 2012-10-04
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 2023-02-04
  • 2014-08-15
  • 2011-05-16
相关资源
最近更新 更多