Clojure宏返回两个或多个s表达式

Clojure宏返回两个或多个s表达式,clojure,Clojure,Clojure中有没有一种方法可以编写一个宏(或使用现有宏)来返回两个或多个s表达式 例如。假设我正在尝试生成前10个正方形: (map * (range 10) (range 10)) 现在我想尝试使用repeat,以便以后可以提供功率(目前为2)作为参数: (map * (repeat 2 (range 10))) 但是,上述操作不起作用,因为repeat返回具有两个范围(而不是两个范围)的单个s表达式 请不要提供“返回前10个方块”函数的替代实现。我对处理这种情况的惯用方法或普遍适用的

Clojure中有没有一种方法可以编写一个宏(或使用现有宏)来返回两个或多个s表达式

例如。假设我正在尝试生成前10个正方形:

(map * (range 10) (range 10))
现在我想尝试使用repeat,以便以后可以提供功率(目前为2)作为参数:

(map * (repeat 2 (range 10)))
但是,上述操作不起作用,因为repeat返回具有两个范围(而不是两个范围)的单个s表达式

请不要提供“返回前10个方块”函数的替代实现。我对处理这种情况的惯用方法或普遍适用的变通方法感兴趣

我想我正在寻找一种方法来实现下面的爆炸:

(explode '( a b c )) ;; evals to a b c
(map * (explode (repeat 2 (range 10)))

单个宏无法执行此操作

宏是一个函数,它接受一个s表达式并将其转换为另一个s表达式。输入可以是表达式的任何序列(符号、灵长类、其他表达式等),输出是插入以代替原始宏调用的单个表达式

一般来说,宏必须围绕映射和转换整个表单的调用

(your-macro-here (map * (repeat 2 (range 10))))

如果您有两个宏,一个生成表达式,另一个包含整个外部形式,那么外部宏可能会找到包含宏结果的单个表达式,在您的示例中是两个范围,并将它们提升到一个级别,成为独立的表达式。我不建议在实践中这样做,它只是用来说明宏的功能

正如Arthur所说,宏不能完全满足您的需求。根据您希望对这些表单执行的操作,变通方法是可能的

如果您只是想计算宏生成的多个表单,例如简化样板代码,则可以将这些多个表单包装为
do
表单:

(defmacro defn-foos [& foos]
  `(do ~@(map (fn [foo] `(defn ~foo [])) foos)))

(defn-foos my-fn-1 my-fn-2)
;; expands as:
;; (do (defn my-fn-1 [])
;;     (defn my-fn-2 []))
如果您希望在函数调用中使用展开的表单作为位置参数,就像您所做的那样,那么您最好将它们包装在
列表中,然后使用
apply
将列表作为位置参数解压到函数中

要了解其工作原理,请注意原始问题中的第二个示例可以使用
apply
进行简单修改:

(apply map * (repeat 2 (range 10)))

你的问题措辞有些混乱。如果您能提供一个您希望看到的语法示例,这将非常有用;目前,您使用的是
map
repeat
,它们在Clojure中已经有了特定的定义。@JohnJ请参阅我文章的更新部分