
When sequence->stream
“eagerly” initiates a sequence, does this imply that it traverses the entire sequence, or just enough to produce the first element?

is it possible to use match
with variables for example, something like… (match codon
((list T A _) ...))
Where T
and A
are already defined values to be eq?
to as opposed to variables to bind?

@massung you probably want to write (== T)
and maybe (== T eq?)

@samth Thanks

I’ve got this xexpr:
(html
(@ (lang "en-gb") (dir "ltr"))
"\n"
(head
"\n"
"\t"
(meta (@ (charset "utf-8")))))
What are these @ symbols saying to me? They’re not in the HTML file. Educate me on this?

@anything that looks like sxml to me

> (xexpr? x)
#t


You must be right! But the predicate above produces #t. Thanks for the pointer! I’ll probably have a better luck now.

I think the xexpr?
predicate is a little too flexible there (I’m not sure if @
is a valid tag name) but unfortunately there’s a lot of overlap between the two encodings

“Initiating” a sequence does not traverse it. It just allocates whatever data structures the sequence uses to keep track of where you are in the traversal. For example initiating a vector sequence might allocate a mutable object that points to your current position in the vector. Sequences can usually be traversed concurrently, so this state is typically traversal-specific.

So it’s not even just enough to produce the first element - it’s just enough to prevent the client from forgetting where they are in the sequence.

@anything The @ means “attributes” ( @ is an at-sign … )

What this means for sequence->stream
is that it gives you an immutable frozen view of a single traversal of a sequence. If you had a sequence that represented “ten random numbers” and gave you different numbers each time you iterated it, applying sequence->stream
would give you a stream that always yields the same ten numbers. Because no matter how many times you traverse the stream, that stream is backed by only a single traversal of the original sequence.

Indeed. I got that from the link above. Thanks for pointing it out, @soegaard2!

Here’s a generator. It works as expected.
(define (make-gen)
(generator ()
(for ([e '("a" "b" "c")])
(yield
(,e (w yes) (x no) (z no))))))r
acket@whatcms.rkt> (define more (make-gen))racket@whatcms.rkt> (more)
’(“a” (w yes) (x no) (z no))
racket@whatcms.rkt> (more)
’(“b” (w yes) (x no) (z no))
racket@whatcms.rkt> (more)
’(“c” (w yes) (x no) (z no))
racket@whatcms.rkt> (more) ; #<void>
racket@whatcms.rkt>
But how can I consume it from within a loop? This doesn't do what I expected.
(define (use-gen)(define more (make-gen))
(for ([ls (more)])
(displayln ls)))
racket@whatcms.rkt> (use-gen)
a
(w yes)
(x no)
(z no)`
It’s as if each element of the first yield-call comes one at a time in the use-gen for loop. (Never used generators before.)
— Idea: I think the use-gen is looping through only the first yield. Perhaps I need a sequence there.

What is it that you expect it to do?

(more)
is going to be the first yielded value of the generator. So that’s what you’re iterating over.

The effect that I expected to get was:
(define (use-gen)
(for ([ls (in-generator
(let loop ([e '("a" "b" "c")])
(when (not (null? e))
(yield
(,(car e) (w yes) (x no) (z no)))(loop (cdr e)))))])
(displayln ls)))
racket@whatcms.rkt> (use-gen)
(a (w yes) (x no) (z no))
(b (w yes) (x no) (z no))
(c (w yes) (x no) (z no))`
But I wanted to write the code that first way.

Okay, so in a for
loop, when you have something like: for ([x xs]) ...)
, x
is bound to each successive value in the sequence xs
. So xs
needs to be a sequence. A generator isn’t a sequence, though.

In your code, you were using (more)
, which is (as I said before) the result of calling the generator — that is, it’s the first thing that the generator returns, which is a list. And a list is a sequence, which is why the code you had runs, but it doesn’t do what you want.

What you need is a sequence that represents each successive call to the generator.

There’s a form named in-producer
that generates a sequence from a function. But that, by itself, probably isn’t quite what you want either, because a generator doesn’t ever really stop.

You could just use in-generator
which makes a sequence instead of generator

So I don’t think there’s a really convenient way to do what you’re trying to do.

@samdphillips Right, but that’s what @anything mentioned above.

Doesn’t a generator produce #<void>
when exhausted?

Would something like (in-producer void the-generator)
work?

@greg The documentation is kind of hard to square with the example that comes right after it.

But in the specific case of this generator — yes.

Ah OK. I just inferred that from their example, I hardly ever use generators.

Me either.

And I actually forgot that in-producer
has the stop
argument, which makes this a lot more convenient.

So yeah — that would work.

In my experience just use in-generator
because most likely you want a sequence.

ugh

Oh — after reading the generator docs again, I realize that I missed a word, and now that I see it, it makes more sense.

I missed reading the use-gen
function

So yeah — after its final yield, a generator will start yielding the return value. And will keep doing so indefinitely.

Yes in-producer
is your friend. I used to use it all the time for reading until I found in-port

So as long as the return value is distinct from a normally yieldable value, you can use that with in-producer
.

In @anything’s example, the return value is eventually void.

Since that’s what a for
gives you.

So, @anything, it would be for ([ls (in-producer (void) more)]) ...
. Note that there are no parens around more
. Because more
is the producer, whereas (more)
is the (first) thing that it produces.

I use in-generator
too much probably. Some things are awkward (or I’m too lazy) to not do in a direct form.

So the way out I found was to not use the for loop. :-)
racket@whatcms.rkt> (define (make-gen)
(generator ()
(for ([e '("a" "b" "c")])
(yield
(,e (w yes) (x no) (z no))))))racket@whatcms.rkt> (define (doit gen)
(define x (gen))
(when (not (void? x))
(displayln x)
(doit gen)))
racket@whatcms.rkt> (doit (make-gen))
(a (w yes) (x no) (z no))
(b (w yes) (x no) (z no))
(c (w yes) (x no) (z no))
racket@whatcms.rkt>`

Let me try in-producer
then

I should have tried my code before posting it :slightly_smiling_face:

Perhaps you could have make-gen
use in-generator
instead of generator
? Then you can use that in the for loop more easily

Does anyone have a good “recipe” for timing out a read? I have a procedure (read-message an-input-port)
that reads some number of bytes over the network and I would like to time out and error or return some timeout value.

@samdphillips sync/timeout

Oh — I had the stop and producer arguments in the wrong order…

for ([ls (in-producer more (void))])

@samdphillips If you’re just reading bytes, you’d use sync/timeout
along with read-bytes-evt
. If your read-message
is doing something more complicated, you’d need to adjust it to produce a synchronizable event.

That’s what I was going to ask

read-message
reads a variable amount of bytes based on the message pretty much

@jaz, but I did catch that. :slightly_smiling_face:

Thanks for the help you all.

I think I misled you by putting them backwards in my “would something like this work”.

@samdphillips Is the code for read-message
too large (or confidential) to post?

@samdphillips That reminds me — but is different from — something I had to figure out: How to attempt to read
an s-expression, but if a complete one isn’t available yet, not get stuck inside the read
. What I came up with, for better or worse: https://github.com/greghendershott/racket-mode/blob/master/racket/interactions.rkt#L34-L53

I can distill it down to something postable. It’s not too much.

One obvious flaw here is the 4096 buffer size, but in the context of REPL reads, it seemed not totally horrible (I hope).

@greg that is what I was starting to try

Just wondering if there was some good community knowledge on this

Maybe you all can point out more flaws and I can get a free code review. :smile:

In the discussion about generators, I was going to say (but it seemed probably OT) that I expected to use generators more when I learned Racket. I think why I haven’t, is I got comfortable using thread and channels and such. So most “concurrency” uses of generators, I end up doing that? idk if that makes sense.

Here is read-message
distilled down. In the actual code there is some error checking, etc. (define (read-message inp)
(match (read-byte inp)
[#x00 (define payload-size (read-byte inp))
(define payload (read-bytes payload-size inp))
(list payload)]
[#x01 'failure]))

(also in the real code there are about 6 more clauses in the match)

Something like: (define (read-message-evt in)
(define (read-payload-evt in)
(replace-evt in
(λ (_)
(define size (read-byte in))
(handle-evt (read-bytes-evt size in) list))))
(replace-evt
in
(λ (_)
(match (read-byte in)
[#x00 (read-payload-evt in)]
[#x01 (handle-evt always-evt (λ (_) 'failure))]))))
Since an event that’s ready for synchronization can become un-ready, this isn’t strictly correct, I guess. If you were worried about that case, I guess you’d need to use read-bytes-evt
to read a single byte for the initial and payload bytes. Maybe?

In the code above, I’m assuming that after the input port becomes ready, the attempt to read a single byte on it will succeed without blocking. Which is generally true.

In my case if the timeout happens the port is closed so partial reads are no big deal.

@jaz Thanks that confirmed the direction I was thinking of going.

I was just playing around with some syntax that would allow you to write this sort of thing in a more direct style. Like https://gist.github.com/97jaz/ec714dfe9b66b674bff53b629b28c9d6

@agj_chile has joined the channel