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

欢迎!请参阅关于页面以获取更多有关此信息的工作细节。

0
Clojure
问题描述

假设我想创建多个绑定并执行一个主体。我可以这样轻松地做到

(let [a 1
      b (inc a)
      c (* b b)]
  [a b c])


但是,如果您想用if-let做类似的事情,由于if-let一次只能接受一个绑定,所以只能通过嵌套完成。

(if-let [a 1]
  (if-let [b (inc a)]
    (if-let [c (* b b)]
      [a b c]
      "error")
    "error")
  "error")


这非常不优雅,因为
1) 与所有绑定都相邻并具有相同缩进的阅读相比,阅读起来不太简单
2) else子句被多次复制。
3) else子句的评估取决于哪个绑定失败。如果a已经绑定了一个值怎么办?如果if-let创建了a的阴影,并且b没有绑定,那么else子句将执行一个不同于在没有第一次if-let中创建阴影时绑定的值。请参看下面的代码示例。

我想要能够这样写

(if-let [a 1
         b (inc a)
         c (* b b)]
  [a b c]
  "error")
=> [1 2 4]

(let [a :original]
  (if-let [a :shadowed
           b false]
           a a))
=> :original


我还希望能够在when-let、if-some和when-some中使用类似的功能。

*提案:*

我重新编写了那些宏,以能够处理多个绑定。如果只提供一个绑定,它们的行为保持相同。如果有多个绑定,它们应该只有在所有绑定通过的情况下才执行主体。在if-let或if-some中,一些绑定通过而另一些失败的情况下,不应将任何绑定泄漏到else子句中。

*补丁:*

- clojure-core v2 8-3-2017.patch - Clojure补丁,包含宏的更新。对于if-let和if-some,我必须添加一些额外的逻辑,以防止它们在有些绑定通过而有些失败时泄漏绑定到else子句。它还包括针对每个宏的一些额外测试。
- core.specs.alpha.patch - core.specs.alpha补丁,与核心规范的等效更新

5 个回答

0

评论者:alexmiller

这与CLJ-2007有什么关系?

0

评论者:justinspedding

我在评论中贴出了对该问题的解决方案代码。然后,你提到了票证的正确格式,并链接到票证创建指南。我认为这意味着您希望制作的票证遵守约定。

此外,本票证是关于修改现有的宏。CLJ-2007是关于创建2个新的宏:if-let* 和 when-let**。

0

评论者:gshayban

值得研究JVM打算如何使用test-and-destructure内联函数。Brian Goetz在对模式匹配的最近一次演讲中提到了这一点(链接:1)

(链接:1) https://www.youtube.com/watch?v=n3_8YcYKScw

0

评论者:justinspedding

更新补丁,当if-let和if-some未提供任何绑定时,简化生成的代码

0
参考: https://clojure.atlassian.net/browse/CLJ-2213(由 justinspedding 报告)
...