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

欢迎!请参阅关于页面以了解该网站是如何运行的更多信息。

0
Clojure

Rich 今天在与用户的交互中提到,他欢迎 clojure.core/range 的 reducer 实现方案。现在我已解决如何使用迭代的问题,我希望今晚能通过函数化简器解决 range 问题。现在先提前开放问题,以便通知其他有兴趣的人。

24 个答案

0

Amalloy 发布的评论:

实现了 range。已附上单独的提交,使 iter 和 range 也成为 seq-able,因为我不知道这是否是期望的。根据您喜好应用它或不应用。

0

Jasonjckn 发布的评论:

Range 应该可折叠

0

Amalloy 发布的评论:

是的,应该这么做到。现在我应该深入研究折叠实施方法!

0

Amalloy 发布的评论:

我应该把这些所有的提交合并到一个吗?我不知道在 JIRA 中这更受青睐,此外,我也不知道 range/iterate 是否应该是 seq-able,或者我应该忽略第二个提交。

0

评论者:richhickey

是的,请合并它们,否则很难看出(我连现有的差异都几乎读不了了:)。range 和 iterate 不应该在 reducers 中是新的特性,而应该是核心函数增强的返回值。增强(例如协议扩展)可能需要通过 reducers 实现,因为没有它无法利用。另外,我对为 'splittable' 创建分配协议还心存疑虑——到目前为止我一直避免这样做。

0

Amalloy 发布的评论:

您是想让 clojure.core/range 返回一个对象(一个 Range),这个对象实现了 Counted 和 Seqable(但并不是懒序列),然后在 clojure.core.reducers 中扩展 CollReduce 和 CollFold 到这个类型?好的,我可以这样做。

我不太明白您所说的分配协议是什么意思。我明白您的观点,我的 fold-by-halves(它接受一个函数)类似于一个只有单个函数的协议,但它并不会比 foldvec 多分配任何东西——我只是把这部分逻辑提取出来,这样在所有可折叠的元素中就不需要重复做 fork/join 的复杂工作了。您有没有其他推荐方案,或者这仅仅是让您感到不安,您还在思考这个问题吗?

0

评论者:richhickey

尽管 vector-fold 会分配子向量,但 halving-fn 必须对所有实现返回一个新的向量。没关系,我认为这不太可能成为瓶颈(因为 fj 总是还需要新的闭包)。请继续操作,但请将 range 和 iterate 维护在核心中。它们是源,而不是转换器,只有转换器(必须与基于序列的对应物不同)必须驻留在 reducers 中。谢谢!

0

评论者:stuart.sierra

推崇一个大补丁文件,尽管这个文件可能包含多个提交,如果这能让意图更清晰的话。

在添加补丁时,更新工单的描述以指明哪个文件是最新的。保留旧的补丁文件作为历史参考。

0

Amalloy 发布的评论:

将迭代和范围移动到 core.clj 中比我想的要复杂。我的计划是只让它们实现 Seqable,这很容易,但它们的实际实例却是 ISeq,因为它们继承了 LazySeq。大量的代码(例如,在 repl 中打印它们)依赖于它们是 ISeq,所以不能简单地忽略。实现所有这些方法(大约三十个)将需要大量的代码,这些代码无法轻松地在 Iteration、Range 以及任何未来添加到 core.clj 中的可减少源之间共享。

我可以写一个像 (defseq Range (链接:开始 结束 步长) Counted (计数 (链接:此) ...) ...) 的宏,它接受正常的 deftype 参数,并添加 ISeq、Collection 等的实现,这些实现是基于 (.seq this),它将是一个 LazySeq。然而,这似乎是一个有点尴尬的方法,我不太想在 core.clj 中滥用它。如果有人有更好的替代方案,我将很高兴听取意见。在 meantime,我将继续进行这个宏实现,以防它最终成为最佳选择。

0

Amalloy 发布的评论:

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

为了创建一个既是惰性序列又是
可减少源的实体,我需要向 core_deftype 添加一个名为 defseq 的宏。
它基本上是将 clojure.lang.LazySeq 作为 clojure
宏重实现,这样我就可以将惰性序列函数“混合”到新类中
中,这需要任何所需方法来减少和折叠。

如果我们想,我们可以使用这个宏在 clojure 中而不是在 java 中实现 lazy-seq,但这是相关的,所以我没有在这个补丁中这样操作。

如前所述评论中所述,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,以便避免破坏像 (defn range-list (link: n) (ArrayList. (range n))) 这样像互操作性函数。如果只需要实现 ISeq(以及 IPersistentCollection),那么这是相当容易管理的。

尽管如此,对于每个新的来源,这仍然是一段令人厌烦的样板代码;如果不将其放入 core_deftype,你能接受一个像 defseq 这样的宏吗?如果可以,似乎最好实现互操作性接口;如果不能,我可以选择跳过它们,并在每个新的来源类型中实现 ISeq、IPersistentCollection 和 Seqable 的 7 个(不,它应该是 9 个)方法。

感谢你指出 clojure.lang.Range 给我——我没想到我们在这里有它。当然,通过实现继承,可以很容易地让 Range、Iteration 等继承自 LazySeq,并从它们扩展协议,但这意味着将功能从 clojure 移动到 java,我认为我们不希望这样做。

我将会为这两种新的类型手动实现 ISeq,并可能在今天稍后附上补丁。

0

Amalloy 发布的评论:

因此,我已经写了一个实现 ISeq 的补丁,但没有实现 Java 集合接口,并且它的大部分功能都正常,但在 clojure.core 和 clojure.lang 的某些部分中肯定有一些假设表示序列是集合。对我来说最明显的是(即,在运行 mvn test 时出现),是 RT/toArray——它测试 Collection,但从未测试 ISeq,这意味着它不愿处理不是集合的 ISeq。依赖于 toArray(例如 to-array 和 vec)的函数现在失败了。

这个补丁涵盖了所有关于此问题的以前的补丁,但由于它留下了一些失败的测试,因此不适合应用——它仅作为中间反馈的意图。

0

评论者:richhickey

如果时间允许的话,请在开发维基中记录您发现的问题、挑战和选项,哪怕是一个简单的表格也极好。我明白这确实是一项富有挑战性的任务,目前我们可能应该选择更为低调的reducers/range和reducers/iterate,并让这两个领域保持独立。我将来某个时候会考虑统一range,因为现在有许多现存的range,如果能够折叠就像现有向量一样,那就太好了。

欢迎来到Clojure问答,在这里您可以向Clojure社区成员提问并获取答案。
...