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 中做了这个更改的工作。结果比我预期的还要糟糕:我没有意识到在引导阶段我们还没有 syntax-quote 或 apply,因此编写一个非平凡的宏展开需要大量的 (list foo (list bar 'local-name)) 以及如此等等。

我相信我写的版本不是最优的,但似乎比直接扩展成正确的东西再进行更多修改要简单些。

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

0

评论者:amalloy

我意识到我可以用命名私有函数而不是匿名函数来做这个,这减少了 defmacro 本身需要生成的混乱。我以为补丁 4 比补丁 3 要好得多,如果 Clojure 实现比 Java 实现更受青睐的话。

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在测试中引起的bug;也许有一个更难混淆的东西。

0

评论者:jafingerhut

Aug 14 2013日期的clj-865-updated-v2-patch.txt与Alan Malloy于2012年6月1日的updated.patch相同。我仅仅是更新了补丁,以适用于最新的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)

...