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样式。
- 我的解决方案是 took &form 元数据,删除 :line/:file 键,然后与返回的元数据合并,&form 优先。我不确定这是否是所有情况下的正确方法,尽管它对 :tag 元数据有效。
- 我通过更改编译器实现这一点,这相当重。应该可能通过调整defmacro进行更改,而不希望更改编译器。然而,我认为这需要更多的工作,并且更难测试(例如,多参数使事情变得复杂)。似乎更优雅的做法是将宏展开视为黑盒,然后对结果进行元数据调整,而不是修改真实的defmacro代码。
- 如果宏展开为的不是IObj,例如整数,那么我的补丁默默地丢弃了调用者的元数据。抛出异常会更好吗?

16 个回答

0

评论者:amalloy

因此,我决定在 clojure.core/defmacro 而不是 clojure.lang.Compiler/macroexpand1 中实现这个更改。这比我预期的要糟糕:我没有意识到在该阶段的引导过程中我们还没有 syntax-quote 或 apply,因此编写非平凡的宏展开需要大量的 (list foo (list bar 'local-name)) 和类似内容。

我相信我写的版本可能不是最优的,但使用 defn 并通过 alter-var-root 来模拟元数据管理似乎比直接扩展到正确的内容要简单。

无论如何,附带的补丁 #3 可以应用于替代 #2,以在 clojure.core 中解决 clojure.lang 中出现的问题。补丁 #1 中添加的测试在任何情况下都通过。

0

评论者:amalloy

我发现可以使用命名私有函数而不是匿名函数来实现这一点,从而减少 defmacro 本身生成的混乱。我认为,如果Clojure实现优先于Java实现,则补丁 4 比补丁 3 纯粹更好。

0

评论者:[email protected]

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

建议的默认宏展开行为比我们目前拥有的更有用,但有几个细节我需要考虑一下

1) 为了获得更有用的默认行为,宏编写者将失去消费其 &form 元数据以及在不受 &form 元数据覆盖的情况下控制结果形式元数据的能力。也就是说,宏不再对其输出形式拥有完全控制权。

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

0

评论者:amalloy

该补丁整合了之前所有针对此问题的补丁。

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

一个悬而未决的问题是,:explicit-meta是否是正确的键?我花了一些时间追踪一个由于忘记关键词而使用:explicit-metadata在测试中造成的错误;或许有更难混淆的东西。

0

评论由:jafingerhut发表

2013年8月14日的clj-865-updated-v2-patch.txt与Alan Malloy的2012年6月1日的updated.patch相同。我只是在测试文件macros.clj中的某些上下文行由于最近的提交而损坏后,简单地将补丁更新为针对最新master版本应用。

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

...