2024 Clojure 状态调查中分享您的想法!

欢迎!请参阅关于页面了解如何使用此功能的相关更多信息。

0
编译器

此补丁更改了与其他宏一起使用时元数据的行为。现在,元数据 &form 将与宏调用 sexpr 的元数据合并。这允许用户在宏调用中对内部或外部形式进行类型提示,并得到更好的结果。以前,直接使用了宏展开的元数据。这不允许以下类型的代码工作,而无需进行反射:

(.trim ^String (when true "hello "))

补丁: 2013-10-11_CLJ-865_Fix-With-Tests.diff
审核: Timothy Baldridge

--------- 实现细节 ----------

http://groups.google.com/group/clojure/browse_thread/thread/2690cb6ca0e8beb8中所述,在给表示宏的表达式类型提示时,如 (.length ^String (doto (identity "x") prn)),会存在一个"意外因素"。这里,doto 宏丢弃了 &form 上的元数据,导致反射查找。这使得表示函数调用表达式的类型提示成为可能,但通常表示宏的表达式则不能。可以将 doto 宏重写为尊重其 &form 元数据,但为现有的所有宏这样做将会非常繁琐且容易出错。相反,我提议修改编译器,以使宏展开自动保留元数据。

附加的第一个补丁为我要提出的操作添加了测试:这个测试失败了。在应用第二个补丁之后,测试通过了。

在接受我的补丁之前,有几个问题需要进一步考虑
- 我不确定是否正确地格式化了 Java 代码。我的编辑器没有正确配置来自动获取 clojure/core 风格。
- 我的解决方案是获取 &form 元数据,删除 :line/:file 键,然后将其与返回的元数据合并,其中 &form 优先级更高。我不确定这在所有情况下是否都是正确的方法,尽管它对于 :tag 元数据有效。
- 我通过修改编译器实现了这一点,这使它相当笨重。如果不想更改编译器,则可以调整 defmacro。然而,我认为这会涉及大量的工作,且更难测试(例如,多参数使情况复杂化)。似乎更好的方法是处理宏展开作为黑盒,然后对该结果进行元数据调整,而不是修改它们的实际 defmacro 代码。
- 如果宏展开成非 IObj 的东西,例如 Integer,那么我的补丁将默默地丢弃调用者的元数据。抛出异常是否会更好?

16 个答案

0

由amalloy发表的评论:

所以我决定在前端的clojure.core/defmacro而不是在clojure.lang.Compiler/macroexpand1中做这个改变。结果甚至比我想的还要糟糕:我没有意识到在这个重建的阶段我们还没有语法引号或apply,所以编写非平凡的宏展开需要大量的(list foo (list bar 'local-name))等等。

我确信我写的版本可能不是最优的,但是相比最初直接扩展到正确的结果,依赖defn然后使用alter-var-root来重新构造元数据管理似乎更简单。

无论如何,附加的补丁#3可以用作#2的替代方案,以在clojure.core而不是clojure.lang中解决问题。补丁#1中添加的测试无论是哪种方式都通过。

0

由amalloy发表的评论:

我意识到可以用一个命名的私有函数而不是匿名函数来做这件事,减少defmacro本身需要生成的混乱。我认为,如果Clojure实现更受青睐,那么补丁4与补丁3相比,会更好。

0

[email protected]发表的评论:

我更喜欢Java中的补丁0002,而不是0003或0004。补丁0002将宏函数调用的知识(特别是额外的 &form 和 &env 参数)集中在一个地方,即 macroexpand1,而不是在core.clj中复制这些知识。注意补丁0001仅仅是测试。

建议的默认宏展开行为比我们目前拥有的更有用,但我还想稍微考虑两个细节:

1) 为了获得更有用的默认行为,宏编写者失去了消费他们的 &form 元数据和在不覆盖 &form 元数据的情况下控制输出形式的能力。也就是说,宏不再完全控制它们的输出形式。

2) 上面提到的规则(1)为:line和:file硬编码了例外,其中 &form 元数据无法覆盖宏返回的结果。

0

由amalloy发表的评论:

此补丁纳入了该问题的所有先前补丁。

在 clj-dev 邮件列表中,Andy Fingerhut 提出了一种新的元数据键,允许宏作者指定“我已经查看他们的 &form 元数据,这正是我想要扩展的内容,请不要再修改元数据。”我已实现这一点,我认为它解决了 Chouser 关于需要一种方法来“跳出”改进默认行为的担忧。

一个悬而未决的问题是,:explicit-meta 是否是应该使用的键?我花费了一些时间追踪出由于遗忘关键字而使用 :explicit-metadata 导致的错误;也许有更不容易混淆的选择。

0

评论人:jafingerhut

2013 年 8 月 14 日的 clj-865-updated-v2-patch.txt 与 Alan Malloy 的 2012 年 6 月 1 日的 updated.patch 相同。我只是更新了补丁,使其apply cleanly to latest master,因为测试文件 macros.clj 的一些上下文行因为最近的提交而变得有问题。

0

评论人:halgari

添加了更新的补丁,该补丁可以用于 master,并从宏的元数据中删除 COLUMN_KEY。

0

评论人:halgari

添加了包含所有修复和一些额外测试的补丁。

0

评论人:richhickey

由于这可能会破坏某些东西,我们只需在宏名称上获取元数据来请求这个功能即可。

(defmacro ^:keep-meta simple-macro [f arg] `(~f ~arg))

或者类似的东西。

0

由amalloy发表的评论:

当然,我会准备好那个补丁。但是,我担心如果这不是默认的,它可能永远不会被使用,我们可能仍然处于当前无需进行更改的情况,即没有任何宏这样做。我不认为任何人会去他们的库中为每个宏添加 ^:keep-meta。

0

由amalloy发表的评论:

我将补丁更新为按照Rich的要求执行,但它在处理引用或私有变量时导致了一个我无法解决的测试回归。希望其他人可以运行测试并找出这里缺少的内容;我的更改应该是可选的,我看不到我哪里出错。

0

评论人:jafingerhut

Alan,您于2013年12月3日提交的补丁clj865.patch在开头和结尾有一些HTML垃圾,但即使移除这些,它今天也不能干净地应用于最新的Clojure master。我明白您说还需要更多的修改,但如果它能够干净地应用,对于希望尝试的其他人来说将更容易。

0

由amalloy发表的评论:

对不起Andy,谢谢你的关注。最近我一直在一个不够友好的开发者电脑上,但今晚我会尝试修复补丁。

0

由amalloy发表的评论:

这里是补丁的修复版本。我已验证,这个补丁可以干净地应用于当前master。

0

由amalloy发表的评论:

为了明确,文件名为clj-865.patch。我没有意识到JIRA不会在评论中明确指出我上传的文件。

0

评论人:jafingerhut

截至Eastwood版本0.2.0,它包含一个新的警告::unused-meta-on-macro,它将在每当将元数据应用于宏调用时发出警告,除了clojure.core/fn,因为它明确使用应用于其上的元数据。https://github.com/jonase/eastwood#unused-meta-on-macro

...