数据/收集中的球拍序列与内置序列

时间:2019-06-07 08:03:43

标签: racket generic-programming

我一直在使用data/collection中的某些接口,到目前为止,我一直很喜欢它。拥有与列表,流和序列之类的不同Racket集合通用的接口确实非常方便-尤其是考虑到此类接口的多样性(否则{{1},list-*vector-*,{ {1}},string-*,...!)。

但是这些接口在Racket中的内置序列中能否很好地发挥作用?具体来说,我遇到了这个错误:

stream-*

=>

sequence-*

函数(require data/collection) (take 10 (in-cycle '(1 2 3))) 返回一个内置的“序列”,而; take: contract violation ; expected: sequence? ; given: #<sequence> ; in: the 2nd argument of ; (-> natural? sequence? sequence?) ; contract from: ; <pkgs>/collections-lib/data/collection/sequence.rkt ; blaming: top-level ; (assuming the contract is correct) ; at: <pkgs>/collections-lib/data/collection/sequence.rkt:53.3 提供的多态in-cycle则期望它自己的特殊序列接口。

在这种情况下,我可以手动定义一个流来替换内置的take,例如:

data/collections

...可行,但是有一个awful lot of built-in sequences defined,所以我想知道是否有更好的,也许是标准/推荐的方式来处理此问题。也就是说,我们是否可以利用数据/集合中定义的序列来利用所有内置序列,就像后者包装其他现有序列(如列表和流)的方式一样?

3 个答案:

答案 0 :(得分:2)

正如@Sorawee Porncharoenwase所述,您可以使用cycle中的data/collection而不是内置的in-cycle

您还可以将sequence->stream应用于in-cycle的结果中, 因为球拍的流既是内置序列,又是data/collection序列。例如,

(take 10 (sequence->stream (in-cycle '(1 2 3 4))))

答案 1 :(得分:2)

在进一步研究之后,我认为我对Racket和data/collection中的序列有了更好的理解。我将尽力总结其他答案和评论中提出的所有要点,并包括我自己的学习。

球拍序列(即内置序列)旨在成为所有有序集合的generic interface,就像使用dict-*函数处理任何词典的方式一样类型,包括哈希。此外,还有许多方便的实用程序提供内置的序列,以使在不同情况下可以轻松处理有序数据,例如从集合中获取的元素序列或从某个输入端口接收的输入序列或序列。从字典中获取的键/值对-这最后一个并不是天生的“有序”集合,但是可以使用内置的序列接口将其视为一个。

因此我们可以认为内置序列具有双重目的:

  1. 成为有序数据的统一接口,并且
  2. 通过在每种情况下提供自然的序列接口实现,使在各种情况下使用序列变得很方便。

现在,尽管从理论上讲内置序列旨在作为有序集合的统一接口,但实际上,由于内置序列的冗长性,例如,它们并不是特别适用于此目的。 sequence-takesequence-length,而不只是我们用于列表的takelength

data/collection序列由于其名称简短而规范,从而解决了该缺点,例如take而不是sequence-take。此外,这些序列还为内置序列提供的许多序列实用程序提供drop-in replacements,例如cyclenaturals而不是in-cyclein-naturals与泛型in函数一起使用,以派生用于迭代的任何序列的惰性版本(例如(in (naturals)))。这些data/collection版本由于不可变而通常更“行为良好”,内置序列不能保证这些版本。结果,在许多情况下,data/collection序列可以被视为内置序列的替换,在很大程度上取代了内置序列的两个目的。

也就是说,在您要处理序列的地方,请考虑使用data/collection序列代替内置序列的,而不是使用的方式内置序列。

在点(2)上,以下是当前可视为数据/收集序列的类型:

  • 列表
  • 不可变哈希表
  • 不可变向量
  • 不可变哈希集
  • 不可变字典

source

足够了,但是还有更多的情况可以推导出常识序列。对于上面未涉及的任何此类情况,内置序列实用程序仍然有用,例如in-hash序列中没有类似物的in-portdata/collection。通常,在许多情况下,我们可以轻松派生内置序列(请参见实用程序here),而不是data/collection序列。在这些特殊情况下,我们可以简单地通过sequence->stream将如此获得的内置序列转换为流,然后通过更简单的data/collection序列接口使用它,因为流可以被视为两种类型的序列。

答案 2 :(得分:1)

有点棘手。此表达式(in-cyle '(1 2 3))的计算结果为球拍序列。 球拍序列与“通用序列”不同(有关数据/收集,请参阅文档)。

当您需要take中的data/collection时,就会得到take,它需要一个通用集合,因此

#lang racket
(require data/collection)
(take 10 (in-cycle '(1 2 3)))

会给你一个错误。

文档说以下内置数据类型可用作集合:

  • 列表
  • 不可变哈希表
  • 不可变向量
  • 不可变哈希集
  • 不可变字典

因此,我们需要将序列(in-cycle '(1 2 3))转换为上述之一。 @capfredf提到的显而易见的选择是sequence->stream

#lang racket
(require data/collection)
(take 10 (sequence->stream (in-cycle '(1 2 3))))

这按预期工作。