请在 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

被选中
 
最佳答案

在什么情况下这会有用?


replayed
其他使用序列解构的相同或相似场景
*我有包含一定范围数据的项序列,我想要边界(例如,最早的和最新的)。我可以用[f (first s), l (last s), r (next (butlast s))]这样的非解构方式做到这一点,但解构使它看起来更整洁。
*我有一个人位队列,需要选择最后一个和倒数第二个项目进行后续处理:[[& init second-item first-item]]

在这些场景中,你可以自己构建选择的项目,但 Clojure 的解构语法也提供了这种方法,使用解构语法是一种好方法,可以一致地完成这些工作,而不需要在一个 let 块中填满所有繁琐的工作。

此外,将解构作为核心语法的一部分,它将支持嵌套,并且任何性能改进都将自动被所有人感受到。
给定顺序(可能非索引)输入,这种情况通常效率不高。通过 spec(通过 s/conform 和正则表达式规范)为更广泛的使用case提供对这类内容的支持。

在您提到的第二种情况中,我认为这甚至不是我们想要支持或鼓励的事情--你只是用这种方式制造了一个性能混乱。

虽然我偶尔看到对这类东西的需求,但它远不如当前支持的场景常见(并且通常对性能来说并不明智),所以我并不确信添加这个是有意义的。
有意义,大致符合我预期的答案。您愿意查看 `destructure` 的补丁,并附上一些性能比较吗?
不,实际上并不感兴趣。我认为你低估了假设尾部位置可变参数的使用场景数量,以及这种更改所需付出的努力。加之没有用例,这根本不值得花费时间去考虑。
太好了,非常感谢。
@Noah 这可以在库中作为一个宏来实现,基本上能带来与直接在 clojure.core 中修复同样的社区效益,而无需陷入直接修补 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` 函数中处理。这就有更多意义。
...