2 votes

Séquences Racket dans les données/collection vs séquences intégrées

J'ai joué avec certaines des interfaces dans data/collection et je l'aime beaucoup pour l'instant. Disposer d'interfaces génériques pour différentes collections Racket comme les listes, les flux et les séquences est vraiment pratique, surtout si l'on considère la diversité des interfaces pour ces types ( list-* , vector-* , string-* , stream-* , sequence-* , ... !).

Mais ces interfaces fonctionnent-elles bien avec les séquences intégrées dans Racket ? Plus précisément, je rencontre l'erreur suivante :

(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

La fonction in-cycle renvoie une "séquence" intégrée, tandis que l'option polymorphe take fourni par data/collections attend sa propre interface de séquence spéciale.

Dans ce cas particulier, je pourrais définir manuellement un flux pour remplacer la fonction intégrée in-cycle quelque chose comme :

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

... qui fonctionne, mais il y a une beaucoup de séquences intégrées définies Je me demande donc s'il n'y a pas une meilleure façon, peut-être standard/recommandée, de gérer cela. En d'autres termes, pouvons-nous tirer parti de toutes les séquences intégrées en termes de séquences définies dans data/collection, de la même manière que cette dernière enveloppe d'autres séquences existantes comme les listes et les flux ?

2voto

capfredf Points 387

Comme l'a mentionné @Sorawee Porncharoenwase, vous pourriez utiliser cycle de data/collection au lieu de l'outil intégré in-cycle .

Vous pouvez également demander sequence->stream aux résultats de in-cycle , puisque le flux d'un Racket est à la fois un intégré et un data/collection séquence. Par exemple,

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

2voto

mindthief Points 2074

Après avoir travaillé un peu plus, je pense avoir une meilleure compréhension des séquences en Racket et en data/collection . Je vais essayer de résumer tous les points qui ont été soulevés dans d'autres réponses et commentaires, et je vais également inclure mes propres apprentissages.

Les séquences Racket, c'est-à-dire celles qui sont intégrées, sont destinées à être une interface générique à toutes les collections ordonnées, de la même manière que vous pouvez utiliser dict-* pour travailler avec n'importe quel type de dictionnaire, y compris les hachages. En outre, il existe également de nombreux utilitaires pratiques qui fournissent des séquences intégrées pour faciliter le travail avec des données ordonnées dans différents scénarios, comme une séquence d'éléments tirés d'une collection, ou une séquence d'entrées reçues sur un port d'entrée, ou une séquence de paires clé-valeur tirées d'un dictionnaire - cette dernière n'est pas intrinsèquement une collection "ordonnée", mais peut être traitée comme telle en utilisant l'interface de séquence intégrée.

On peut donc considérer que les séquences intégrées ont un double objectif :

  1. étant une interface uniforme pour les données ordonnées, et
  2. faciliter l'utilisation des séquences dans divers scénarios en fournissant une interface de séquence naturelle dans chaque cas.

Or, bien que les séquences construites soient censées constituer une interface uniforme pour les collections ordonnées en théorie, en pratique, elles ne sont pas particulièrement utilisables à cette fin en raison de leur verbosité, par ex. sequence-take y sequence-length au lieu de la seule take y length que nous utiliserions pour les listes.

data/collection Les séquences corrigent ce défaut grâce à leur nom court et canonique, comme par exemple take au lieu de sequence-take . En outre, ces séquences fournissent également remplacements ponctuels pour de nombreux utilitaires de séquences fournis par les séquences intégrées, tels que cycle y naturals au lieu de in-cycle y in-naturals ainsi qu'un générique in pour dériver des versions paresseuses de toute séquence à utiliser dans l'itération (comme la fonction (in (naturals)) ). Ces data/collection sont généralement plus "efficaces" du fait qu'elles sont immuables, ce que les séquences intégrées ne garantissent pas. En conséquence, data/collection Les séquences peuvent être considérées comme un remplacement pour les séquences intégrées dans de nombreux cas, reprenant largement le premier des deux objectifs des séquences intégrées.

Autrement dit, dans les endroits où vous avez affaire à des séquences, envisagez d'utiliser data/collection séquences au lieu de de séquences intégrées, et non comme un moyen de travailler avec séquences intégrées.

Sur le point (2), cependant, les types suivants sont actuellement traitables comme des séquences de données/collecte :

  • listes
  • tables de hachage immuables
  • vecteurs immuables
  • ensembles de hachage immuables
  • dictionnaires immuables
  • ruisseaux

( source )

C'est suffisant, mais il existe encore d'autres scénarios dans lesquels une séquence de bon sens pourrait être dérivée. Pour tous les cas de figure qui ne sont pas couverts ci-dessus, les utilitaires de séquence intégrés sont toujours utiles, tels que in-hash y in-port qui n'ont pas d'analogues dans data/collection séquences. En général, il existe de nombreux cas dans lesquels nous pouvons facilement dériver une séquence intégrée (voir les utilitaires aquí ) mais pas un data/collection séquence. Dans ces cas particuliers, nous pourrions simplement convertir la séquence construite ainsi obtenue en un flux via sequence->stream et l'utiliser ensuite via la méthode plus simple data/collection l'interface de séquence, puisque les flux peuvent être traités comme des séquences de l'un ou l'autre type.

1voto

soegaard Points 6541

C'est un peu délicat. Cette expression (in-cyle '(1 2 3)) s'évalue à une séquence Racket. Les séquences Racket sont différentes des "séquences génériques" (voir la documentation sur les données et les collections).

Lorsque vous avez besoin take de data/collection vous obtenez le take qui s'attend à une collection générique, donc

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

vous donnera une erreur.

La documentation indique que les types de données intégrés suivants fonctionnent comme des collections :

  • listes
  • tables de hachage immuables
  • vecteurs immuables
  • ensembles de hachage immuables
  • dictionnaires immuables
  • ruisseaux

Nous devons donc convertir la séquence (in-cycle '(1 2 3)) dans l'une des catégories ci-dessus. Comme le mentionne @capfredf, le choix évident est le suivant sequence->stream .

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

Cela fonctionne comme prévu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X