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

选中
 
最佳答案

在什么场景下这会有用?

by
再次展示 by
其他序列解构使用的相同或类似场景
* 我有一系列具有某些范围数据的项,我想得到边界(例如,最早和最新)。我可以使用 [f (first s), l (last s), r (next (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 实现中存在很多假设尾部带有 rest 参数的事情。
by
啊哈,Clojure 实现内部。我以为这只在 `destructure` 函数中处理。这解释得更合理。
...