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

欢迎!请参阅关于页面以了解更多有关如何使用本站的信息。

0
Clojure
问题描述

假设我想用 let 创建多个绑定并执行一个体。我可以这样做

(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 没有绑定,那么使用不同值绑定的 a 就会执行 else 子句(请参见下面的代码示例)。

我想写成这样

(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个绑定时,简化生成的代码的更新的补丁

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