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

欢迎!请参阅关于页面,了解ώς这也是如何工作的更多信息。

+3
Clojure
编辑

我看到有几个代码实例使用clojure.lang.RT/iter来获取Clojure集合的迭代器。

(iterator-seq (clojure.lang.RT/iter [1 2 3]))

例如

https://github.com/noprompt/meander/commit/d2310daaa485afb4e15ceda72aa57f97ea90f284

以及

https://github.com/wilkerlucio/cljc-misc/blob/bb3c8016cace18db5caa5fe0aa5df7a507935f8d/src/main/com/wsscode/misc/coll.cljc#L262

为了与 Babashka 的Clojure兼容,我想知道我是否应该公开 clojure.lang.RT。我并不完全确信应该这么做,因为 clojure.lang.RT 可能是 Clojure 的实现细节。

相反,也许 Clojure 可以将 RT/iter 方法作为 clojure.core 函数公开?

我“领悟”了我的本地 .m2对于clojure.lang.RT的使用情况,并排除了 clojure 本身

[clojure.lang.RT/loadClassForName 15]
[clojure.lang.RT/iter 5]
[clojure.lang.RT/loadLibrary 4]
[clojure.lang.RT/assoc 4]
[clojure.lang.RT/classForName 3]
[clojure.lang.RT/load 2]

请注意,ClojureScript 有一个 iter 函数

$ plk
ClojureScript 1.10.597
cljs.user=> (iter [1 2 3])
#object[cljs.core.RangedIterator]
cljs.user=>

$ clj
Clojure 1.10.1
user=> (iter [1 2 3])
Syntax error compiling at (REPL:1:1).
Unable to resolve symbol: iter in this context

2 个答案

0

我同意@borkdude的观点,有一个核心函数用于这个语言中的常见项目会很好,这将使其更便携。

这不是什么大问题,但 在 CLJS 中也有transformer-iterator,这将通过应用变换器创建一个新的迭代器。这也会很好,希望在这个特性上也能保持一致。

by
为什么需要这样的 *why*?当前面临的问题是什么?
by
`transformer-iterator`更具体,可能可以避免。我带来它是由于我在CLJS实现中使用它。但想到这一点,对于我的情况`eduction`几乎以相同的方式工作,我可以继续使用它。
by
`eductions`封装了迭代,并提供了一件安全地在线程间传递的东西,因此绝对是首选。
0
by

RT应该被视为内部实现,不应直接调用。

迭代器通常非常不像Clojure。它们是有状态的并且通常不适合并发。当可以将其使用限制在某个其他调用(特别是transducer上下文)中时,Clojure会依赖它们。

(iterator-seq (clojure.lang.RT/iter [1 2 3]))看起来不好,(seq [1 2 3])看起来在很多方面都更好。如果有某个用例让人们想要制作迭代器,我对那个问题感兴趣,但在这个地方我没有看到它。

> 它们两个都是关于构建迭代函数的,这些函数在那个项目中从没有被调用过。

Alex,我想澄清,这是不正确的。Meander确实使用`iter`函数,通过生成的宏代码来实现一些更容易(代码生成更简单)的语义,在某些情况下。虽然我后来意识到 không cần sử dụng `iter` có thể thực hiện điều này, nhưng lúc đó tôi không có giải pháp đó và `iter` đã giải quyết vấn đề của tôi。

Bạn đã công nhận những trường hợp này tồn tại và đây là lý do tại sao một số phần cứng Clojure chưa được " khóa lại". Bạn công nhận việc triển khai JVM của `iter` do Wilker cung cấp là " hoàn hảo". Tuy nhiên, bạn không nghĩ rằng nó nên là phần của API công khai hoặc không nghĩ rằng đó là một ý tưởng tốt, nhưng bạn không cung cấp lý do cụ thể tại sao bạn nghĩ như vậy.

> Tôi không nghĩ rằng `iterator` là một hàm nên được sử dụng rộng rãi hoặc quảng bá.

Tôi đồng ý. Antique cơ sở dữ liệu chứa rất nhiều hàm không được sử dụng rộng rãi cũng không được quảng bá, nhưng chúng vẫn có giá trị. Nghĩa là không thể promotional hay các trường hợp sử dụng rộng rãi không thể là lý do để loại bỏ `iter`.

> Những giá trị của Iterate, trong general, rất không Clojure.

Đây là một vị trí độc đoán, duy nhất. Nó giống như, ý kiến của bạn, bạn. :^)

Clojure bao gồm rất nhiều cơ hội để sử dụng "trạng thái và không phải tốt cho tính đồng bộ" trong thư viện cơ sở và, theo công thức của bạn, có mục đích làm cho chúng có thể truy cập. Những điều này, từ góc nhìn của tôi, nó.statistics bao gồm những điều này "không Clojure".

Bây giờ, đểконечно же, hỏi, tiêu chí ngẫu nhiên một hàm phải đạt được trước khi "ớn" được xem xét là gì?
ĐManyToOne, quyết định những gì cần được đưa vào API cơ sở dữ liệu / ngôn ngữ chính là vấn đề搜集人们在遇到的问题并筛选以发现模式,然后根据频率,严重性,解决方案的难度等因素,确定哪些问题是最重要的需要解决。

Cách tốt nhất để cung cấp phản hồi cho quá trình đó là mô tả rõ ràng nhất về vấn đề bạn gặp phải. Khi bạn gặp vấn đề này trong Meander, bạn muốn một bộ điều khiển sao? Vấn đề thực tế là gì? Bạn đã nghĩ đến những gì khác? Tại sao chúng không đủ?

威尔克关于需要在集合类型中实现其迭代器方法的描述,是一个有用的例子。将`iter`添加到核心是一个可行的解决方案。另一个方案是编写自己的函数,使用现有的Java API,就像他所做的那样。另一个方案可能是将构建自定义集合类型的通用需求封装到Clojure或库内部。我确实注意到这里的需要范围并不常见(大多数人不会创建自定义集合类型),他没有使用`iter`函数,而是使用现有的Clojure/Java API解决了问题,而且我没有发现其他人遇到同样的问题(但也许他们存在)。

我总体上对迭代器持反对态度。与seq和reducelables不同,迭代器既危险又具有命令式特性,而这一点并非偶然,它并不是Clojure API的一部分。这不仅是我的观点,也是Rich的观点,这是我在转播的。他在很多地方都写过了/谈论过这一点。

* https://clojure.org/about/functional_programming#_extensible_abstractions
* https://clojure.org/reference/sequences
* https://clojure.org/news/2012/05/08/reducers
* https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureIntroForLispProgrammers.md

此外,在我们设计和实现transważory的过程中,我们对此进行了深入的讨论,这极大地依赖迭代器,但在使用它们时封装了它们以确保安全。

尽管如此,我认为这并不是不可行的,但在我看来,这种需要的程度似乎不足以克服这个偏见。如果你想改变我的观点,那就带给我问题吧。
by
以下所有内容都夹在“我后来得到一个更新的解决方案,它不依赖于`iter`,但在我使用`iter`解决这个问题的时候,它做到了我需要它做得。”这句话中。

> 当在Meander中遇到这种情况时,为什么你需要迭代器?

严格来说,我最初并不“需要”迭代器,但最终它“解决了”我的问题,以下我将详细说明。

>  你遇到了什么实际问题?

这里有几个交织的问题。Meander有一个称为模式替换的概念,你可以把它想象成模式匹配的对偶。匹配将模式应用到对象上,并返回一组绑定,替换将绑定应用到模式上,返回一个对象。特别是重复模式,其中包含一种称为“记忆变量”的变量类型,其编译就会出现这个问题。

内存变量是指绑定到FIFO(先进先出队列)的变量。内存变量在模式“分散”或来自FIFO的第一个值中出现时,“分散”或更新变量与FIFO剩余元素的绑定。这个过程一直持续到FIFO变为空,这时被称为“耗尽”。当内存变量出现在重复的模式中(比如Kleene星号)时,重复的模式会生产值,直到至少有一个内存变量未被耗尽。当重复模式编译成Clojure代码时,会检查模式中是否包含内存变量。如果包含,则针对每个内存变量编译迭代器,每个迭代器都可以通过`hasNext`进行检查以判断是否耗尽,当然,可以使用`next`进行值的分散。虽然这不是一个理想solution,但我想要的语义以这种方式实现起来很方便。

你还考虑了其他什么因素吗?

最初,我尝试了一个纯solution,但这导致了很多复杂性和头疼。这更多的是与依赖`iter`的设计质量差有关,而不是与纯方法有关。

我也尝试过`volatile!`,但这在某些情况下产生了错误的结果。

过了一段时间后,我认为考虑使用数组,但因为`iter`已经存在,并完成了我想让它完成的事情,所以我并没有去麻烦它。

为什么它们不够充分?

因为要么存在一些复杂的问题,作为维护者,我不想涉及,要么这些问题导致了语义实现的错误。
by
>  我不认为CLJS有`iter`是个好主意。

这是问题的关键。CLJS总是被当作Clojure的一种方言来处理,导致了许多类似的情况。虽然我理解有人对正式指定语言的一部分有偏见,但至少有一个最小程度的原语定义和默认解析器符号的定义,可以在空命名空间中,可能会对未来实现这些问题起到缓和作用。我个人认为,`ns`宏是问题的一部分,因为它是无处不在的(`in-ns`更基本,但很少使用;CLJS需要它),并且它引用了核心,其内容是基于实现认为应该存在的内容的任意基础;像这样的问题是一个自然的结果。

如果未来的语言设计包括原语的最小定义,以便可以轻松实现平台特定符号的清晰分离,那么这些关于CLJ和CLJS或其他实现之间差异的问题可能会消亡。

关于这些,我也有经验。在过去5年中,我*部分地*实现了一个Clojure解释器/编译器,用于Ruby 2.X.X,一个小型的Clojure符号解释器,以及一个Clojure的部分评估器。在每个情况下,我都未能完成项目,因为缺乏语法和语义的明确语言定义。例如,有一些特殊形式,如`case*`,没有文档,需要检查编译器以确定其语义。

无论如何,我这里没有提出要求。我只是想分享我的观察。我认为Clojure有这样一个未来,其中像这样的问题不存在。作为近十年专业和作为爱好编程这个语言的某人,我认为对语言的某些规范将铺平通往那个未来的道路。
我无法代表开发和维护Clojure的核心团队,但鉴于过去十年中,其他人在各种公共论坛上多次提出了Clojure规范的疑问,我怀疑:(a)Clojure核心团队除了在实现中包含的文档字符串和clojure.org今天提供的众多官方文档页面(以及仍然计划编写的那些页面)之外,对编写此类规范不感兴趣;(b)如果这是真的,唯一可能被编写的规范将由不在该团队中的人创建,而Clojure核心团队将没有遵循它的理由。
...