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和正则spec)已经提供了对这类更广泛用例的支持。

在你提到的第二种情况中,我认为我们甚至不希望支持或鼓励这种做法——这种做法只会使性能陷入困境。

虽然我偶尔见过一些这样的需求,但它们的出现频率远低于当前支持的案例(并且通常因性能问题而不建议),所以我不太确信增加这种功能是合理的。
这个答案很合理,大致符合我的预期。你愿意看一下对`destructure`的修复补丁,并附上一些性能比较吗?
by
不是真的感兴趣。我觉得你低估了那些假设尾位置剩余参数的地方以及进行此类更改的努力。结合使用案例的缺乏,这根本不值得浪费时间。
by
太好了,非常感谢。
by
@Noah 这可以在库中的宏来实现,几乎能够带来同样的社区收益,而不必陷入修补 clojure.core 的麻烦。尽管语言小队不希望将缓慢的操作定格在语法中,但程序员也珍惜那些使其更为清晰的解构场合。
by
@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` 函数中处理。这更有意义。
...