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 没有被绑定,则 else 子句会使用不同的 a 的值执行,如果 a 在第一个 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报告)
...