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

欢迎!有关如何工作的更多信息,请参阅 关于页面

0 投票
编译器

此补丁更改了宏与宏调用 sexpr 合并用时元数据的行为。现在,元数据 &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 中进行这次变更。结果比我预期的还要糟糕:我没有意识到在引导阶段我们还没有 syntax-quote 或 apply,所以在编写非平凡的宏展开时需要大量的 (list foo (list bar 'local-name)) 等等。

我相信我所写的版本可能并不理想,但似乎更简单地将它放在 defn 上,然后使用 alter-var-root 来模拟元数据管理,比一开始就正确展开要好。

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

0 投票

由 amalloy 发布的评论:

我意识到可以用命名私有函数而不是匿名函数来做这件事,这样可以减少 defmacro 本身要生成的混乱。我认为,如果Clojure实现优先于Java实现,那么补丁4比补丁3要好。

0 投票

[email protected] 发布的评论:

我更喜欢 Java 中的补丁 0002 而不是 0003 或 0004。补丁 0002 将如何调用宏函数的知识(特别是额外的 &form 和 &env 参数)放在一个地方,即 macroexpand1,而不是在 core.clj 中 duplicating that knowledge。

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

1) 为了获得更有用的默认值,宏编写者失去了消费他们的 &form 元数据并且在不被 &form 元数据显示的背景下控制结果的元数据的行使。也就是说,宏不再完全控制它们的输出形式。

2) 上文提到的规则(1)有一个硬编码的例外:行号和文件名,在此处 &form 元数据无法覆盖宏返回的结果。

0 投票

由 amalloy 发布的评论:

此补丁将所有先前针对该问题的补丁合并在一起。

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

一个悬而未决的问题是,:explicit-meta 是否是正确的键?我曾花了一些时间追踪一个因为我忘记关键字而使用 :explicit-metadata 在我的测试中产生的错误;也许有更难混淆的东西。

0 投票
by

由:jafingerhut 发表的评论

2013年8月14日的 clj-865-updated-v2-patch.txt 与 Alan Malloy 的 2012年6月1日的 updated.patch 相同。我只是在测试文件 macros.clj 的一些上下文行由于最近的提交而出错后,简单地将补丁更新到最新的 master 上。

0 投票
by

由:halgari 发表的评论

添加了针对 master 的工作更新的补丁,并删除了宏的元数据中的 COLUMN_KEY。

0 投票
by

由:halgari 发表的评论

添加了包含所有修复和一个补充测试的补丁。

0 投票
by

由:richhickey 发表的评论

鉴于这可能会破坏某些东西,我们只需在宏名称上获取元数据以请求此内容。

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

或者某个东西

0 投票
by

由 amalloy 发布的评论:

当然,我会整理这个补丁。但我担心,如果这不是默认设置,它将永远不会被使用,我们仍然处于现在的情况,即没有宏这么做。我预见不到任何人会遍历他们的库,在每个宏上添加 ^:keep-meta。

0 投票
by

由 amalloy 发布的评论:

我已经按照Rich的要求更新了补丁,但它在处理引用变量或私有变量时引发了测试回归,我无法解决这个问题。希望有人能运行这些测试并找出这里缺失的部分;我的更改应该是可选的,但我觉得我出错的地方。

0 投票
by

由:jafingerhut 发表的评论

Alan,您2013年12月3日的补丁文件clj865.patch开头和结尾有部分HTML冗余,即使在移除这些冗余后,它也无法干净地应用于今天最新的Clojure master版本。我理解您说它还需要更多的工作,但如果它能够干净地应用,其他人想要尝试它就会容易得多。

0 投票
by

由 amalloy 发布的评论:

对不起Andy,感谢您的提醒。我最近一直用不太友好的计算机 developers,但我今晚会尝试修复补丁。

0 投票
by

由 amalloy 发布的评论:

这是我修复补丁的一个方法。我已验证它适用于当前的master。

0 投票
by

由 amalloy 发布的评论:

为了澄清,文件名为clj-865.patch。我没有意识到JIRA不会清楚表明我评论中附带的文件。

0 投票
by

由:jafingerhut 发表的评论

Eastwood版本0.2.0包括一个新警告::unused-meta-on-macro,当将元数据应用到宏调用时将发出警告,除了clojure.core/fn之外,它明确使用应用到的元数据。https://github.com/jonase/eastwood#unused-meta-on-macro

...