Последовательности ракеток в данных / сбор против встроенных последовательностей - PullRequest
2 голосов
/ 07 июня 2019

Я играл с некоторыми интерфейсами в data/collection, и мне это до сих пор нравится.Наличие общих интерфейсов для различных коллекций Racket, таких как списки, потоки и последовательности, действительно удобно - особенно с учетом разнообразия интерфейсов для таких типов (list-*, vector-*, string-*, stream-*, sequence-*, ...!).

Но хорошо ли работают эти интерфейсы со встроенными последовательностями в Racket?В частности, я сталкиваюсь с этой ошибкой:

(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 ожидает свой собственный специальный интерфейс последовательности.

В этом конкретном случае я мог бы вручную определить поток для замены встроенного in-cycle, что-то вроде:

(define (in-cycle coll [i 0])
  (stream-cons (nth coll (modulo i (length coll)))
               (in-cycle coll (add1 i))))

... который работает, но существует очень много встроенных последовательностей, определенных , поэтому мне интересно, есть ли лучший, возможно, стандартный / рекомендуемый способ справиться с этим.То есть, можем ли мы воспользоваться всеми встроенными последовательностями в терминах последовательностей, определенных в данных / сборе, так же, как последний объединяет другие существующие последовательности, такие как списки и потоки?

Ответы [ 3 ]

2 голосов
/ 09 июня 2019

Поработав еще немного, я думаю, что у меня есть лучшее понимание последовательностей в Racket и в data/collection.Я постараюсь обобщить все пункты, которые были подняты в других ответах и ​​комментариях, а также включу мои собственные уроки.

Последовательности ракеток, то есть те, которые встроены,предназначен для универсального интерфейса для всех упорядоченных коллекций, так же, как вы можете использовать функции dict-* для работы с любым типом словаря, включая хэши.Кроме того, есть также много удобных утилит, которые предоставляют встроенные последовательности, облегчающие работу с упорядоченными данными в различных сценариях, например, последовательность элементов, взятых из коллекции, или последовательность входов, полученных на некотором входном порте, или последовательностьпар ключ-значение, взятых из словаря - последняя из которых по своей природе не является «упорядоченной» коллекцией, но которую можно рассматривать как одну, используя встроенный интерфейс последовательности.

Таким образом, мы можемПредставьте, что встроенные последовательности имеют двойную цель:

  1. как единый интерфейс для упорядоченных данных, и
  2. , позволяющий удобно работать с последовательностями в различных сценариях, предоставляя естественный интерфейс последовательностиреализации в каждом конкретном случае.

Теперь, хотя встроенные последовательности теоретически предназначены для унифицированного интерфейса для упорядоченных коллекций, на практике они не особенно пригодны для этой цели из-за их многословия, например sequence-take и sequence-length вместо take иlength, которые мы использовали бы для списков.

data/collection последовательности устраняют этот недостаток, поскольку их имена являются короткими и каноническими, например take вместо sequence-take.Кроме того, эти последовательности также обеспечивают вставные замены для многих утилит последовательностей, предоставляемых встроенными последовательностями, таких как cycle и naturals вместо in-cycle и in-naturals, наряду с универсальнымin функция для получения отложенных версий любой последовательности для использования в итерации (например, (in (naturals))).Эти data/collection версии, как правило, более "хорошо себя ведут" благодаря своей неизменности, что встроенные последовательности не гарантируют.В результате во многих случаях последовательности data/collection можно рассматривать как замену для встроенных последовательностей, в значительной степени взяв на себя первую из двух целей встроенных последовательностей.

То есть в тех местах, где вы имеете дело с последовательностями, рассмотрите возможность использования data/collection последовательностей вместо встроенных последовательностей, а не как способ работать с встроенными последовательностями.

В точке (2), однако, ниже перечислены типы, которые в настоящее время могут обрабатываться как последовательности данных / сбора:

  • списки
  • неизменяемые хеш-таблицы
  • неизменных векторов
  • неизменных хеш-наборов
  • неизменных словарей
  • потоков

( источник )

Это достаточно, но есть еще больше сценариев, в которых может быть получена последовательность здравого смысла.Для любых таких случаев, которые не охвачены выше, утилиты встроенных последовательностей по-прежнему полезны, такие как in-hash и in-port, которые не имеют аналогов в data/collection последовательностях.В целом, во многих случаях мы можем легко получить встроенную последовательность (см. Утилиты здесь ), но не последовательность data/collection.В этих особых случаях мы могли бы просто преобразовать полученную таким образом встроенную последовательность в поток через sequence->stream, а затем использовать ее через более простой интерфейс последовательности data/collection, поскольку потоки можно обрабатывать как последовательности любого типа.

2 голосов
/ 07 июня 2019

Как уже упоминалось @Sorawee Porncharoenwase, вы можете использовать cycle из data/collection вместо встроенного in-cycle.

Вы также можете применить sequence->stream к результатам in-cycle, поскольку поток Racket является как встроенной, так и data/collection последовательностью. Например,

(take 10 (sequence->stream (in-cycle '(1 2 3 4))))
1 голос
/ 07 июня 2019

Это немного сложно.Это выражение (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))))

Это работает, как и ожидалось.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...