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

欢迎!请参阅关于页面以获取更多关于该工具的信息。

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和正则表达式spec)已经支持了这类更广泛的使用场景。

在你提到的第二种情况下,我认为我们甚至不希望支持或鼓励这种情况——你只是在用一个像那样的事情制造性能混乱。

虽然我偶尔见过对这类东西的需求,但它远比当前支持的使用场景要少得多(并且对于性能来说往往不妥),因此我不认为添加这一点是有意义的。
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` 函数中处理。
...