
@oscar88 has joined the channel

by “different language” do you mean languages implemented atop of Racket?

@laurent.orseau Interestingly, gen:stream
, which is much simpler to use, is even faster than define-sequence-syntax
+ :do-in
which is supposed be to faster…
#lang racket
(define-sequence-syntax in-list+rest
(lambda () #'in-list+rest/proc)
(lambda (stx)
(syntax-case stx ()
[[(x r) (_ lst)]
#'[(x r)
(:do-in
([(l) lst])
(unless (list? l)
(raise-argument-error 'in-list+rest "list?" l))
([l l])
(not (null? l))
([(x r) (values (car l) (cdr l))])
#true
#true
[r])]]
[_ #f])))
(define (in-list+rest/proc l)
(for/list ([(x r) (in-list+rest l)]) (list x r)))
(struct in-list+rest** (xs)
#:methods gen:stream
[(define (stream-empty? self)
(null? (in-list+rest**-xs self)))
(define (stream-first self)
(define xs (in-list+rest**-xs self))
(list (car xs) (cdr xs)))
(define (stream-rest self)
(in-list+rest** (cdr (in-list+rest**-xs self))))])
(define (in-list+rest* xs)
(unless (list? xs)
(raise-argument-error 'in-list+rest* "list?" xs))
(in-list+rest** xs))
(define xs (range 1000000))
(time (for ([x (in-list+rest xs)])
x))
(time (for ([x (in-list+rest* xs)])
x))
This outputs:
cpu time: 396 real time: 433 gc time: 309
cpu time: 106 real time: 111 gc time: 2
in Racket, and
cpu time: 233 real time: 236 gc time: 194
cpu time: 97 real time: 101 gc time: 0
in Racket CS.

Woah, this is very surprising to me. How come then?

(it’s also very cool :slightly_smiling_face: )

I don’t know!

Oh, actually, what’s going on seems to be that there’s a lot of GC activity going on in in-list+rest
.

What’s weird is that swapping lines doesn’t help.

Does it help to remove the list?
check? (speed-wise that is not gc-wise)

The list?
check in both versions are at the top-level, so it’s not an issue. But if you call list?
on every iteration, there will be a clear performance degradation in Racket CS. I just reported the issue at https://github.com/racket/racket/issues/3109

I am surprised by the difference. If anything I would have guessed at the opposite times.

Can you add a (collect-garbage) before each loop?

I just did that last minute lol

On Racket CS, the difference disappears. On Racket BC, define-sequence-syntax
+ :do-in
is still far worse.

I guess it depends when the gc happens then

so that means the :do version does a lot of gc, but the struct one doesn’t?

Yep

The gen:stream
version doesn’t trigger the GC as much.

There must be some copying going on, that’s mostly optimized away, but not entirely?

I tried swapping the two variants around, and it is always the case that :do-in
takes the GC hit.

How does gen:stream work under the hood?

I don’t know…

Can you compare with the bare let loop variant I posted before?

It shouldn’t trigger the GC unnecessarily I suppose

@sorawee I don’t think your :do-in
syntax is being used at all. You’re looking for uses of the form [(x r) (_ lst)]
, but your use site has the form [x (in-list+rest xs)]
, which doesn’t match the pattern. So it falls back to using in-list+rest/proc
, which has to allocate the whole list. If you fix that issue, I expect the :do-in
version to be far more efficient than the one using gen:stream
.

Ahhh

Yep, you are absolutely right. When I invoke it correctly, the result is:
cpu time: 105 real time: 107 gc time: 8
cpu time: 5 real time: 6 gc time: 0
where the below one is :do-in
.

Dumb question possibly, but in the Racket FFI can I send a Racket function into C as a callback?

Yes.

How? Do I just pass it as an argument to a function that expects a _fun?

Will racket wrap it with the relevant type checking?

@pavpanchekha Check _cprocedure https://docs.racket-lang.org/foreign/foreign_procedures.html


Also ffi-callback

@pavpanchekha basically, it just works. @soegaard2 usually you don’t need to use _cprocedure
, you can just use _fun
.

Thanks - it has been a while since I used it. I keep forgetting the details. Too bad dyoo never finished his tutorial.

Also I keep forgetting Asumu wrote one: http://prl.ccs.neu.edu/blog/2016/06/27/tutorial-using-racket-s-ffi/

Nice!

Classic Racket

In Typed Racket how can I require in syntax from an untyped module?

(specifically, what is the syntax to require in include-template
from web-server/templates
?)

Good catch @lexi.lambda!