请在 Clojure 2024 年调查! 中分享您的想法。

欢迎!请查阅 关于 页面,了解更多关于如何使用本站的信息。

0
Clojure

Rich 今天在 IRC 中提到,他欢迎一个 clojure.core/range 的调减器实现。既然我已经弄清楚了如何进行迭代,我想今晚会完成对 range 的调整。提前提出这个问题是为了宣布我的打算,供任何其他人感兴趣的人参考。

24 答案

0

amalloy 的评论:

实现了 range。已附加一个单独的提交,将 iterate 和 range 也变为 Seqable,因为我不知道这是否是所需的。根据您的喜好应用或放弃。

0

jasonjckn 的评论:

range 应该是可折叠的

0

amalloy 的评论:

是的,应该是这样的。现在是时候深入研究折叠实现了!

0

amalloy 的评论:

我应该将这些提交合并成一个吗?我不知道 JIRA 上更受欢迎的是什么,也不知道是否应该将 range/iterate 变为 seqable 或仅在第二个提交中删除。

0

评论者:richhickey

是的,请将这些合并在一起,否则很难看到(我现在的差异输出几乎看不清了:)。range和iterate在reducers中不应是新颖的,而应该是增强核心函数的返回值。增强(例如协议扩展)可以通过需要reducers来实现,因为如果没有它就无法利用。此外,我对'allocation'协议的想法仍不确定——到目前为止,我一直避免使用它。

0

amalloy 的评论:

所以您想让clojure.core/range返回一个对象(一个Range),该对象实现了Counted和Seqable(但不仅仅是lazy-seq),然后在clojure.core.reducers中扩展CollReduce和CollFold到该类型?好的,我可以做到。

我不太明白您所说的分配协议是什么意思。我理解您的观点,我的fold-by-halves函数与具有单个函数的协议类似,但它并不比foldvec已经所做更多——我只是提取了那个逻辑,这样就不需要在所有可折叠的对象中重复fork/join的麻烦工作。您有其他建议吗,或者这只是您感到不安的事情,您还在思考中?

0

评论者:richhickey

虽然vector-fold分配子向量,但halving-fn对于所有实现必须返回一个新的向量。没关系,我认为它不太可能主导(因为fj需要新的闭包)。请继续,但把range和iterate保留在核心。它们是源而不是变换器,并且只有变换器(它们必须与基于seq的对应物不同)必须存在于reducers中。谢谢!

0

评论者:stuart.sierra

preferably, prefer a single large patch file, although that file may contain multiple commits if this makes the intent clearer.

当添加补丁时,更新票据的描述,表明哪个文件是最新的。保留旧的补丁文件以供历史参考。

0

amalloy 的评论:

将迭代和range移动到core.clj中比我想象的要困难。我的计划只是让他们实现Seqable,这并不难,但他们实际上是ISeq的实例,因为它们继承自LazySeq。许多代码片段(例如,在REPL中打印它们)都依赖于它们是ISeq,所以我不能简单地忽略它们。实现所有这些方法(大约三十个)需要大量的代码,这些代码无法在Iteration、Range以及未来添加到core.clj中的任何可还原源之间轻松共享。

我可以编写一个宏,比如(defseq Range (link: start end step) Counted (count (link: this) ...) ...),它接受正常的deftype参数,并在(.seq this)的基础上添加ISeq、Collection等实现的实现,这将是一个LazySeq。然而,这似乎是一个相当不自然的方案,我不太愿意让core.clj变得杂乱。如果有人有更好的替代方案,我将很高兴听到。在此之前,我将继续进行这个宏的实现,以防它最终是最好的选择。

0

amalloy 的评论:

-- 此补丁包含了此问题以及CLJ-992的所有以前补丁 --

为了创建一个既是懒序列又是可还原源的
对象,我需要在core_deftype中添加一个名为defseq的宏。
它基本上是clojure.lang.LazySeq的宏重实现,这样我就可以将懒序列函数“混合”到
具有所需减少和折叠方法的新的类中。
如果愿意,我们可以用这个宏在clojure中实现lazy-seq,而不是用java,但这与此无关,所以我

在这个补丁中没有这样做。

如前述评论中所述,defseq可能不是正确的方法,但这是在提出更好的方法之前的一个解决方案。

0

amalloy 的评论:

我不小心在这个补丁中包含了一个drop-while的实现,这是我为了确保我理解这一切是如何工作的而试验的。我想我暂时可以保留它,因为它有效且有用,但如果它现在不需要,我可以删除它或将其移动到一个新的JIRA任务中。

0

评论者:richhickey

好的,我认为这个补丁已经走上轨道了。必须有更好的方法。让我们从:我们不能操作core/deftype或将lazy-seq作为宏重新实现开始。range的返回值不一定要LazySeq,它只需要是一个lazy seq,即实现ISeq(7个方法,而不是30个),它可以通过将其现有实现外包出去来实现。它还可以实现一些新接口,用于reducer逻辑的使用。clojure.lang.Range仍然存在,这也是另一种方法。在这些事情上采取极其保守的方法。

0

amalloy 的评论:

好了,感谢您的反馈 - 我很高兴我知道上一个补丁可能是错误的,所以进行了修改 :)。我本以为需要实现与LazySeq相同的Java集合接口,如java.util.List,以避免破坏像(range n) (ArrayList.)这样的互操作性函数。如果仅实现ISeq(从而实现IPersistentCollection)就足够了,那么这还是可以管理的。

尽管如此,对于每个新的源文件,编写样板代码仍然麻烦;如果不将宏defseq放入core_deftype中,您是否会接受它?如果是这样,似乎最好实现互操作性接口;如果不是,我可以跳过它们,并为每个新源类型实现ISeq、IPersistentCollection和Seqable的7(是不是像9个?)个方法。

感谢您向我指出clojure.lang.Range - 我没想到我们那里有这个。当然,在实现继承下,容易让Range、Iteration等继承自LazySeq并从它们扩展协议。但这意味着将功能从clojure移动到java,这我认为我们不想做。

我将在今天晚些时候为这两种新类型合在一起编写一个仅实现ISeq的手动补丁,并将其附加。

0

amalloy 的评论:

所以我写了一个补丁来实现了ISeq,但没有实现Java Collection接口,它大多数时候都是有效的,但clojure.core和clojure.lang的一些部分确实假定了序列是集合。对我最明显的是(即它在运行mvn test时出现),RT/toArray - 它测试了Collection,但永远不会对ISeq进行测试,这意味着它不愿意处理非集合的ISeq。依赖于toArray的函数(例如to-array和vec)现在失败了。

这个补丁包括了此问题的所有以前的补丁,但由于它遗留了一些失败测试,因此不适用于应用程序 - 它仅适用于中间反馈。

0

评论者:richhickey

如果时间允许,请在开发者维基上总结您发现的问题、挑战和选项,这将非常有帮助(即使是简单的表格也很好)。我知道这是一个挑战性的任务,在这个阶段,我们或许应该选择更为适度的reducers/range和reducers/iterate,让他们各自独立。我希望在某个时刻统一range,因为有很多现存的range我们希望能够折叠,就像现有的vector一样。

欢迎来到Clojure Q&A,在这里您可以向Clojure社区成员提问并收回答案。
...