1
votes

Playing around with generators and pattern matching in racket I run into the following error while practicing lazily destructuring a collection and I can't figure out what the error is nor why it happens.

  (require racket/match)
  (require racket/generator)
  (require data/collection)
  (sequence->list
   (in-generator
    (let recur ([seq '(1 2 3)])
      (match seq
        [(sequence) (void)]
        [(sequence next next-rest ...)
         (yield next)
         (recur next-rest)]))))

Gives me the following error:

sequence->list: contract violation
  expected: sequence?
  given: #<sequence>
  in: the 1st argument of
      (-> sequence? (listof any/c))
  contract from: 
      <pkgs>/collections-lib/data/collection/collection.rkt
  blaming: /var/folders/g4/0st3r3c513n6ymf2nkw11ml40000gn/T/ob-racket-CFPotf
   (assuming the contract is correct)
  at: <pkgs>/collections-lib/data/collection/collection.rkt:64.3
  context...:
   /usr/local/Cellar/minimal-racket/7.7/share/racket/collects/racket/contract/private/blame.rkt:347:0: raise-blame-error
   /usr/local/Cellar/minimal-racket/7.7/share/racket/collects/racket/contract/combinator.rkt:324:9
   /usr/local/Cellar/minimal-racket/7.7/share/racket/collects/racket/contract/private/arrow-val-first.rkt:486:18
   "/var/folders/g4/0st3r3c513n6ymf2nkw11ml40000gn/T/ob-racket-CFPotf": [running body]
   temp35_0
   for-loop
   run-module-instance!
   perform-require!

Without the generator and if I'm just doing (cons next (recur next-rest)) everything works fine so it shouldn't have anything to do with my pattern matching code. But then again, I'm pretty confident with generators and have done things like this plenty of times, just without the pattern matching bit. I am pretty sure that this should work but have no clue why I'd be getting this error nor even what it means.

1

1 Answers

2
votes

This is because the notion of sequence from data/collection is slightly different from sequence in racket. The sequence->list function from data/collection doesn't always work on sequences from racket or racket/generator, so you'll need to use the sequence->list from racket instead.

One way to do that, is to avoid importing sequence->list from data/collection:

#lang racket
(require racket/match)
(require racket/generator)
(require (except-in data/collection sequence->list))
(sequence->list
 (in-generator
  (let recur ([seq '(1 2 3)])
    (match seq
      [(sequence) (void)]
      [(sequence next next-rest ...)
       (yield next)
       (recur next-rest)]))))

This produces '(1 2 3) instead of the error you were getting.

Another way to fix this is to convert the racket notion of sequence into the data/collection version, which is closer to the racket notion of stream. You can do this with sequence->stream.

#lang racket
(require racket/match)
(require racket/generator)
(require data/collection)
(sequence->list
 (sequence->stream
  (in-generator
   (let recur ([seq '(1 2 3)])
     (match seq
       [(sequence) (void)]
       [(sequence next next-rest ...)
        (yield next)
        (recur next-rest)])))))

This also produces '(1 2 3).

It might seem redundant to have sequence->list and sequence->stream, but think of it more like data/collection-sequence->list and racket-sequence->data/collection-sequence.

Although it's kind-of inconvenient to have to carry around 2 different notions of sequence while both are called just "sequence". If you want you can import the data/collection stuff with a prefix to mark them as separate, such as dc:

#lang racket
(require racket/match)
(require racket/generator)
(require (prefix-in dc: data/collection))
(sequence->list
 (in-generator
  (let recur ([seq '(1 2 3)])
    (match seq
      [(dc:sequence) (void)]
      [(dc:sequence next next-rest ...)
       (yield next)
       (recur next-rest)]))))

Depending on how the rest of your project looks you might want different things for your style.