请在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
reshown by
其他序列解构使用的相同或类似场景
* 我有一个数据范围的一些项的序列,我想要边界(例如最早和最晚)。我可以不用解构,使用[f (first s),l (last s),r (next (butlast s))],但解构更为优雅。
* 我有一个后进先出队列,想要选择最后一个和倒数第二的项目来处理:[[& init second-item first-item]]

在这些场景中,自己构造所选的项目是可能的,但使用Clojure所有解构方式都可以这样做。使用解构语法是一种优雅且一致的方式来完成这项工作,不需要在let块中填写所有繁忙的工作。

除此之外,将其作为核心语法的一部分,它就可以嵌套使用,所有的性能提升都将自动为所有人所感受到。
by
对于(可能非索引的)顺序输入,这类场景通常效率不高。目前spec(通过s/conform和正则表达式规格)提供了对这些更广泛场景的支持。

在你提到的第二个案例中,我认为这不值得我们支持或鼓励——你只是在用这种方法制造一个性能混乱。

虽然我偶尔看到过类似的需求,但这种场景比目前支持的场景要少得多(而且在性能上通常是不明智的),所以我不确定这是否有必要添加。
by
这很有意义,大致是我预期的答案。你愿意查看一个修补方案,并附上一些性能比较吗?
by
不,并不太感兴趣。我认为您低估了假设尾部位置参数的位置数量以及进行此类更改所需付出的努力。这加上缺乏用例,并不值得花费时间。
by
太好了,非常感谢。
by
@Noah 这种情况可以作为库中的一个宏来实现,几乎可以带来同等程度的社区利益,而不必陷入修补 clojure.core。虽然语言团队不太想将缓慢的操作作为语法固定下来,但程序员也重视在这种情况下提高的清晰度。
by
@pbwolf 我也考虑过这一点。也许我会试试。

@alexmiller 考虑到这一点,我对您提到的存在许多假定余参数以及所需努力的说法感到有些困惑。问题是人们依赖于 Clojure 读取器在余参数不在尾部位置时抛出错误吗?
如上所述,如果需要,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]
我谈论的是 Clojure 实现中有很多东西都假设了尾部的 rest 参数。
啊哈,Clojure 实现内部。我本以为这仅仅是在 `destructure` 函数中处理。这使得很多事情都更加明了。
...