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

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

0
语法和读取器
编辑

当前,Clojure 允许存在包含 &rest 参数的解构模式。

user=> (let [[a b & c] (range 5)] [a b c])
[0 1 (2 3 4)]

Python 允许这样做,还可以将所谓的“通配符”放在前面和中间位置(PEP 说明

>>> a, *b, c = range(5)
>>> a
0
>>> c
4
>>> b
[1, 2, 3]

Clojure 是否考虑过类似的设计?它可以看起来像这样:

user=> (let [[a & b c] (range 5)] [a b c])
[0 (1 2 3) 4]

我认为这可以通过核心函数当前的解构方式来实现,但也许我忽略了某些细节。

1 个答案

+1

被选中
 
最佳答案

在什么情况下这将是有用的?

by
重新显示 by
其他序列解构应用相同或相似的场景
* 我有一串带有某些范围数据的项,我想要界限(例如,最早和最新)。我可以通过 [f(s的第一个),l(s的最后一个),r((butlast s)的下一个)] 来实现这一点,但解构让它更简单。
* 我有一个后进先出队列,并想选择最后一个项和倒数第二个项进行后续处理:[[& init second-item first-item]]

在这些场景中,您可以自己构造选定的项目,但使用Clojure的所有解构也是可行的。使用解构语法是一个愉快且一致的方法,可以实现这一点,而无需在let块中填满所有工作。

此外,如果将其作为核心语法的一部分,它将可嵌套使用,并且所有人都能自动感受到性能的提升。
by
针对有序(可能不是索引的)输入,此类场景通常效率不高。现在在spec(通过s/conform和正则规范)中已提供对这些更广泛场景的支持。

在您提到的第二种情况下,我认为这不是我们想要支持或鼓励的事情 - 您只是用类似的东西制造了一个性能混乱。

虽然我偶尔见过类似的需求,但它远不如目前支持的案例那样常见(并且通常对性能不利),因此我不确定添加这一点是有意义的。
by
这很合理,也大致是我预期的答案。您愿意查看一个包含性能比较的`destructure`补丁吗?
不是真的感兴趣。我认为你低估了假设尾位置可变参数数量的地方和这种改变所需付出的努力。加上缺乏用例,这根本不值得花时间。
太棒了,非常感谢。
@Noah 它可以作为库中的宏来实现,基本上对社区有同样的好处,而不需要修改 clojure.core。虽然语言小队不倾向于将缓慢的操作内嵌在语法中,但程序员也重视在需要清晰度的情况下使用解构。
@pbwolf 我也想到了这一点。也许我会试试。

@alexmiller 思考了一下,我对你说有很多地方假设了可变参数以及所需努力的表述感到有些困惑。问题是人们依赖于 Clojure 读取器如果可变参数不在尾位置时抛出错误吗?
by
如上所述,如果需要,spec 和 conform 已经可以处理这些。

(let [{:keys [a b c]} (s/conform (s/cat :a int? :b (s/* int?) :c int?) (range 5))] [a b c])

;;=> [0 [1 2 3] 4]
by
我谈论的是在 Clojure 实现,有很多假设尾部尾部剩余参数的东西。
by
啊哈,在 Clojure 实现内部。我原以为这只有在 `destructure` 函数中被处理。这更有意义。
...