请在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子句将执行与first 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补丁,对于核心规范,有等效的更新

5 个回答

0

评论者:alexmiller

这与此有关联?

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