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子句将执行与如果第一个if-let中a没有被遮蔽时不同的值绑定的a。(请参见下面的代码示例)

我想能写成这样

(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补丁,包含对core.specs的一致更新

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报告)
...