【问题标题】:Clojure macro to return two or more s-expressionsClojure 宏返回两个或多个 s 表达式
【发布时间】:2013-04-03 19:56:23
【问题描述】:

在 Clojure 中有没有办法编写一个宏(或使用现有的)返回两个或多个 s 表达式?

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

(map * (range 10) (range 10))

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

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

但上述内容不起作用,因为 repeat 返回具有两个范围而不是两个范围的单个 s 表达式。

请不要提供“返回前 10 个方块”功能的替代实现。我对处理此类情况的惯用方法或普遍适用的解决方法感兴趣。

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

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

【问题讨论】:

  • 您的问题措辞有些混乱。如果您能提供一个您希望看到的语法示例,将会很有帮助;目前,您使用的 maprepeat 在 Clojure 中已经有了特定的定义。
  • @JohnJ 看到我帖子的更新尾

标签: clojure


【解决方案1】:

单个宏无法做到这一点。

宏是一个函数,它接受一个 s 表达式并将其转换为另一个 s 表达式。 输入可以是任何表达式序列(符号、基元、其他表达式等)和输出是一个插入到原始宏调用位置的表达式。

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

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

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

【讨论】:

    【解决方案2】:

    正如 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 []))
    

    如果您想在函数调用中使用扩展形式作为位置参数,就像您所做的那样,那么您最好的选择可能是将它们包装在 list 中,然后使用 apply 将列表解压缩为函数的位置参数。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 2019-04-29
      • 1970-01-01
      相关资源
      最近更新 更多