
I don’t see it exported from utils-and-no-gui.rkt, which only exports the typed Plot-Metrics<%>
. But otherwise it sounds like a case of double instantiation, once in gui the other in no gui. This might need to be resolved within plot rather than on import, but I’m not sure.

Have you looked at the contents of the linked PR? It is not exported in the main codebase, but I exported it as part of the Pull Request I linked — unfortunately that does not work.

Hm, sorry for being slow. I was reading this quickly on my phone and that’s not ideal for PRs. Ok, I see better what you mean now. Does it fail too if you use (except-in plot plot-metrics<%>)
in the pr90.rkt test?

Wow - thx :)

Is there a library that implements stream-partition
(like the partition
in racket/list
)

?

(define (stream-partition pred s)
(values (stream-filter pred s)
(stream-filter (compose not pred) s)))

A more complete example: #lang racket
(define s (stream 1 2 3 4 5 6 7 8 9 10))
(define (stream-partition pred s)
(values (stream-filter pred s)
(stream-filter (compose not pred) s)))
(let-values ([ (s1 s2) (stream-partition odd? s) ])
(for ([ n (in-stream s1) ])
(printf "~a" n))
(printf "\n")
(for ([ n (in-stream s2) ])
(printf "~a" n)))

That is not ideal unfortunately… I would prefer that pred
is called once per element as it might be expensive and may have side effects

I see. What would you expect the API to be then? In other words, can you provide an example use of your ideal stream-partition
?

It’s not easy… I had in mind something like haskell’s partition ( https://www.stackage.org/haddock/lts-18.17/base-4.14.3.0/src/Data-OldList.html#partition ) but one would probably need to make use of promises or something like that to implement it in racket and I am not very fluent with those myself

Consider a stream of integers that you want to partition into even?
and (not even?)
. If the stream contains all odd?
integers, then to compute stream-empty?
on the even?
stream will require consuming the entire original stream, right?

yes

I think in the general case (like a lot of other stream functions) you just state that it won’t terminate in cases like that.

My hunch is you’d want to create something specific to your use case, since it appears a general stream solution would have some undesirable performance characteristics.

@samdphillips but if the requirement is to only evaluate the predicate once per element, then it seems you’d be forced to cache the entire stream, right?

(in worst case)

Since stream is a generic interface/property a custom partitioned stream is probably what you want. The most direct implementation that I can think of right now would be to use a thread and async channels.

@badkins yes

Might as well convert the stream to a list and partition that then.

If you used async channels with a limit you could do some sort of early termination (because the buffer filled)

re: thread impl; since you could do this with threads there is probably a continuation based solution that could be performed.

so the function I have in mind has the following behavior
> (let-values ([(x y)
(stream-partition
(lambda (x)
(displayln "prop")
#f)
'(1 2 3)])
(displayln (stream-empty? x))
(displayln (stream-empty? y)))
prop
prop
prop
#t
#f

(screwed up the parens but I hope it makes sense)

I think @samdphillips is right

I’d be curious how a solution using threads compares to: (define (stream-partition pred s)
(let*-values ([ (lst) (stream->list s) ]
[ (l1 l2) (partition pred lst) ])
(values (in-list l1)
(in-list l2))))

Probably depends a lot on the distribution of pred?
and (not pred?)

Also how long the list is.

I would probably only use it if I had a lot of external data coming in via a sequence or stream, and was either accumulating it or just keeping a small window.

Seems like providing a “true” and “false” callback would be the way to go typically, unless you need this to be used specifically as a stream for other purposes.

Anyway, I think we’ve plumbed the depths :)

Yep a lot depends on the “source”/"producing" side, as well as the “destination”/"consuming" side of whatever problem you’re working on. I think it’s hard to say without more context.

As a handy-wavy comment, I’ve really come to appreciate Racket channels (async and plain) as well as its synchronization primitives. When I must deal with concurrency. Or prefer to use concurrency to make something easier to express.

A not-horrible template for quite a few things seems to be: (define ch (make-channel)) ...+
(thread
(λ ()
(for ([v (in-producer ___)])
(channel-put ch) ...+))) ...+
(thread
(λ ()
(sync ch ...+)))

where in-producer
could be something like in-port
etc.

And where the sync
might wrap the channel event(s) with things like handle-evt
or whatever.

@cperivol you could try this https://gist.github.com/samdphillips/974df804ca07d8a5323d2a67d8613fcc

I probably could have made it simpler with a promise instead of managing the mutable state.

Ok I wrote a version with promises. It’s a little simpler. (same url)

Nice! Thanks @samdphillips!

@samdphillips in your first version, am I correct in observing that stream-partition
will immediately consume the entire original stream and place the contents into the two async channels?

And if so, is it also possible that the splitter
thread will do that before the two streams are returned in the values
expression?

Oh yeah I didn’t intend it to consume the whole stream eagerly. In fact there should be a more complicated protocol to handle that.

@badkins Excellent Catch

Can you query an async channel to see if it’s empty? If so, you could pause (sync?) in that case i.e. just make sure both channels have at least one unconsumed value ?

Hmm.. doesn’t look like that’s possible.

async-channel-try-get

As long as your stream doesn’t contain #f
:stuck_out_tongue:

Yeah, but won’t that also remove the value from the channel?

So you only do that when the client stream needs the “current” element. So it would do something like: (cond
[(async-channel-try-get ach) => values]
[else
(channel-put req-ch #t) ;; signal to splitter that this stream needs an element, and wait for one in the ach
(async-channel-get ach)])

Ugh there is also a bug with getting stream-rest
in that implementation

As I am reworking this “example” I would definitely not do it this way in real code. I would just go straight to channels and not deal with streams.

The <https://gist.github.com/samdphillips/974df804ca07d8a5323d2a67d8613fcc#file–00_stream-partition-rkt|first module in the gist> now correctly handles stream-rest
and has a simple “more-items-please” protocol to avoid eagerly consuming the source stream.

It probably has a million edge cases, and will probably eat your cat if the partitioned streams are used from multiple threads.

Other options: One simple way would be to memoize the predicate and use @badkins’s version with stream-filter
: (define (memoized-predicate p?)
(define memo-pad (make-hash))
(λ (x)
(hash-ref memo-pad x
(λ ()
(define val (p? x))
(hash-set! memo-pad x val)
val))))
(define (stream-partition p? s)
(define p?* (memoized-predicate p?))
(values
(stream-filter p?* s)
(stream-filter (λ (x) (not (p?* x))) s)))
And here’s a version that doesn’t memoize the predicate (since space usage is uncontrolled with the former example). Instead, you memoize each step of the iteration with a promise: (define (stream-partition p? s)
(cond
[(stream-empty? s)
(values empty-stream empty-stream)]
[else
(define s0 (stream-first s))
(define s* (stream-rest s))
(define promise (delay (stream-partition p? s*)))
(define-syntax-rule (yes)
(let-values ([(xs _) (force promise)]) xs))
(define-syntax-rule (no)
(let-values ([(_ ys) (force promise)]) ys))
(cond
[(p? s0)
(values (stream-cons s0 (yes)) (no))]
[else
(values (yes) (stream-cons s0 (no)))])]))

What about this approach?
(define checked-s
(for/stream ([elem (in-stream s)])
(list (pred elem) elem)))
(define trues
(for/stream ([entry (in-stream checked-s)]
#:when (first entry))
(second entry)))
(define falses
(for/stream ([entry (in-stream checked-s)]
#:unless (first entry))
(second entry)))
(values trues falses))
I’d like to make this a bit more complex to support multiple-valued streams, but it seems like it should manage to avoid forcing the whole stream. (I haven’t tested it….)

Oh, well, I “simplified” that second version a bit right before I posted it, but the simplification isn’t correct, since the promise is forced outside of a stream-cons

If you add back in the stream-lazy
s that I removed… (define (stream-partition p? s)
(cond
[(stream-empty? s)
(values empty-stream empty-stream)]
[else
(define s0 (stream-first s))
(define s* (stream-rest s))
(define promise (delay (stream-partition p? s*)))
(define-syntax-rule (yes)
(let-values ([(xs _) (force promise)]) xs))
(define-syntax-rule (no)
(let-values ([(_ ys) (force promise)]) ys))
(cond
[(p? s0)
(values (stream-cons s0 (yes)) (stream-lazy (no)))]
[else
(values (stream-lazy (yes)) (stream-cons s0 (no)))])]))

@rokitna I like that idea

Hi,
Recently I found that the https://pkgs.racket-lang.org/package/dracula\|dracula package (for acl2 development) had failed compiling since v8.0, because of the rewrite of htdp-lib/test-engine. I’ve been trying to fix this issue, but am not very familiar with the library of test-engine, especially the high level design behind this rewrite (for instance, I found test-engine/scheme-gui
and test-engine/test-info
had been removed, but didn’t know which alternatives to use).
So is there any document I could refer to please? Thanks!