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

欢迎!请参阅 关于 页面以了解更多关于这是如何工作的信息。

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 中实现这个更改。结果甚至比我想的还要糟糕:我没有意识到在引导阶段我们还没有 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] 发表的评论:

我更喜欢 Java 中的补丁 0002,而不是 0003 或 0004。补丁 0002 在 macroexpand1 中保留了对调用宏函数的调用知识(特别是额外的 &form 和 &env 参数),而不是在该 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 相同。我只是更新了补丁,以便在测试文件 macros.clj 中的一些上下文行由于最近的提交而变坏后,可以干净地应用到最新的主分支。

0

评论者:halgari

添加了一个更新的补丁,该补丁针对主分支工作,并从宏的元数据中删除 COLUMN_KEY。

0

评论者:halgari

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

0

评论者:richhickey

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

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

或者类似的东西

0

由 amalloy 发表的评论:

是的,我会把这个补丁放在一起。不过,我担心如果不是默认的,它将永远不会被使用,我们实际上还是处在现在这种没有宏正确执行的状态。我预见不到有人会去检查他们的库并在每个宏上添加 ^:keep-meta。

0

由 amalloy 发表的评论:

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

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

...