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 元数据,但为现有的每个宏这样做将非常繁琐且容易出错。因此,我建议更改编译器,以自动保留宏展开的元数据。

附加的第一个补丁添加了对建议行为的测试:此测试失败。应用第二个补丁后,测试通过。

在接收我的补丁之前,有几点 worth 进一步考虑:
- 我不确定我是否正确地格式化了 Java 代码。我的编辑器没有正确配置以自动获取 clojure/core 风格。
- 我的解决方案是取出 &form 元数据,删除 :line/:file 关键字,然后将它与其他返回的元数据合并,其中 &form 优先级更高。虽然这个方法适用于 :tag 元数据,但我不确定它是否适用于所有情况。
- 我通过更改编译器实现了这一目标,这在某种程度上是相当复杂的。如果不需要更改编译器,则可能可以通过调整 defmacro 来实现,但这将需要大量工作,并且测试更困难(例如,多态调用会使情况复杂化)。似乎将宏展开视为一个黑盒,然后再对其进行元数据调整要好一些,而不是修改它们的实际 defmacro 代码。
- 如果宏展开的内容不是 IObj,如 Integer,那么我的补丁会静默地丢弃调用者的元数据。抛出异常是否更好?

16 个回答

0

由amalloy发表的评论:

所以我决定直接在clojure.core/defmacro而不是在clojure.lang.Compiler/macroexpand1中做这个改动。结果比我预期的还要糟糕:我没有意识到在引导阶段我们还还没有syntax-quote或apply,因此编写一个非平凡的宏展开需要大量的(listfoo (list bar 'local-name))之类的操作。

我相信我写的版本可能不是最优的,但似乎是使用defn堆叠,然后使用alter-var-root来处理元数据管理比一开始就展开到正确的样子要简单。

总之,附上的patch #3可以代替#2应用于clojure.core而不是clojure.lang来解决问题。附带的patch #1中的测试两种情况下都通过。

0

由amalloy发表的评论:

我意识到可以用命名私有函数而不是匿名函数来做这个,从而减少defmacro本身需要生成的杂乱。我认为,如果Clojure实现比Java实现更受青睐,那么Patch 4比Patch 3要严格得多。

0

[email protected]发表的评论:

我更喜欢Java中的patch 0002而不是0003或0004。Patch 0002将调用宏函数的(特别是额外的 &form 和 &env 参数)知识保留在一个地方,即 macroexpand1,而不是在 core.clj 中重复这些知识。Note patch 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相同。我简单地更新了补丁,以便在测试文件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发表的评论:

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

0

评论者:jafingerhut

Alan,你于2013年12月3日发布的补丁clj865.patch在开头和结尾有一些HTML垃圾,但即使移除这些内容,它也无法干净地应用于今天的最新Clojure主版本。我明白你说它还需要更多的工作,但如果它能够干净地应用,其他想尝试的人会更容易。

0

由amalloy发表的评论:

抱歉Andy,谢谢你指出。最近我没有在开发者友好的电脑上,但我今晚会尝试修复补丁。

0

由amalloy发表的评论:

这里是补丁的修复方法。我已经验证了它可以干净地应用于当前的主版本。

0

由amalloy发表的评论:

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

0

评论者:jafingerhut

截至Eastwood版本0.2.0,它包括一个新警告::在宏调用上应用未用元数据,它会在将元数据应用于宏调用时生成警告,除了clojure.core/fn,该函数明确使用了应用到的元数据。https://github.com/jonase/eastwood#unused-meta-on-macro

...