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

欢迎!请参阅关于页面获取更多有关如何使用此功能的详细信息。

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

选择
 
最佳答案

在什么场景下这将是有用的?

其他使用序列解构的相同或类似场景
* 我有一个包含一些数据区间的项目序列,我想要边界(比如最早的和最新的)。我可以通过不用解构的[f (first s),l (last s),r (next (butlast s))]实现这一点,但解构使得它更优雅。
* 我有一个后进先出队列,并希望选择最后项目和倒数第二个项目来处理:[[& init second-item first-item]]

在这些场景中,您可以自己构建所选项目,但使用Clojure的所有解构也都可以做到这一点。使用解构语法是避免在let块中填充大量繁琐工作的一种好方法,并且是一致的方式。

与此相关,通过使其成为核心语法的组成部分,它将可以嵌套使用,并且性能改进将自动被所有人感受到。
对于提供的顺序输入(可能是非索引的),这类用例通常效率不高。对于这些更广泛的应用场景,现在可以通过spec(通过s/conform和正则表达式规范)支持此类功能。

在您提到的第二种情况下,我认为我们甚至不希望支持或鼓励这种情况 - 这只是使用类似的东西造成性能问题。

虽然我偶尔看到对这类东西的需求,但它比目前支持的情况(还有性能不良的情况)要少得多,所以我不确信添加这一点是有意义的。
很有道理,大致就是我预期的答案。你愿意看看与性能比较有关的 `解构` 补丁吗?
不,实际上并不感兴趣。我认为你低估了那些假定尾位置有可变参数数量和进行此类更改所需的努力。再加上缺乏用例,这并不意味着值得花费时间。
谢谢。
@Noah 这可以在库中使用宏来处理,几乎能带来相同程度的社区效益,而不需要打扰到 clojure.core 的修补。虽然语言队并不热衷于将慢操作奉为语法,但程序员也重视在能带来清晰度的情况下使用解构。
@pbwolf 我也考虑过这一点,也许我会试试。

@alexmiller 在想了一段时间后,我对你说有许多地方假定使用了可变参数以及所需的努力程度感到有些困惑。是不是问题在于人们依赖于 Clojure 读取器在可变参数不在尾位置时抛出错误?
如上所述,如果你的需要此功能的话,规范和符合(spec and 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]
我讲的是在 Clojure 实现中,有许多东西假设尾部有余参数(rest args)。
哦,在 Clojure 实现中。我原以为这只在 `destructure` 函数中处理过。这解释得通多了。
...