
@strika has joined the channel

how would I construct a procedure that collects all keyword arguments, but additionally has existing ones? so like, as an example, for (define (func x #:y y #:keyword-hash kw-hash)
(list x y kw-hash))
(func 3 #:y 4 #:bleh 'blah)
; (list 3 4 #hash((#:bleh . 'blah)))
obviously this is not how define
works, and I’m not sold on this syntax, but the idea stands

Look at keyword-apply/dict
and the simpler keyword-apply
.

absolutely, yeah, it’s about constructing the procedure and not applying a procedure with keywords, unless I’m misreading

There’s currently no way to do that easily

The best you got is make-keyword-procedure

I mean I’m already using Alex Knauth’s kw-utils

but that doesn’t support adding kwargs not collected into the hash

I guess I can write yet another macro

I wrote this a while back: https://groups.google.com/g/racket-users/c/3_Vc3t0fTGs/m/HpLZQCwADQAJ

right, this is pretty close to what I want, thanks

actually, this is exactly what I want

thank you @sorawee

Make a package!

I am trying to wrap a C function akin to strdup
. Returns a string to be freed by the user. Just opened https://github.com/racket/racket/issues/3833 because the only example in the docs I could find that’s related doesn’t work with CS and could possibly be improved. I can do something like:

I’ll fix the docs. Meanwhile, the answer is to make the return type _pointer
, which you can cast
to _string
and then free
.

So, the _string
as a return type is not copied?

Casting to _string
will create a copy from the _pointer
content.

Using _string
as a return type will also copy — which gives you a valid string, but loses the opportunity to free
the pointer.

I think I’ve probably written a _string/then-free
type once or twice.

testing

(define _string/free (make-ctype _pointer #f (lambda (x) (begin0 (cast x _pointer _string) (free x)))))
(define strdup (get-ffi-obj “strdup” #f (_fun _string -> _string/free)))
(for ([i (in-naturals 1000)]) (strdup “hello”))

Didn’t know casting would copy…

from the top of your head, will this solution also work in bc?

I see the documentation for cast
mentions the call to malloc
.

Thanks.

Yes, this solution should work in both CS and BC.

Thanks

@hazel Here’s another version (minimally tested) and some notes. This is fun!

In #lang scribble/lp2
, is there a way to get @defproc[(foo ...)]
to register as the link target for a function foo
defined within a chunk
in the same file?

Reasoning that lp2 puts all scribble content in a submodule doc
declared with module*
I thought I could use @(require (for-label (submod "..")))
but that results in
standard-module-name-resolver: too many ".."s in submodule path: (submod (quote scribble-lp-tmp-name) "..")

Maybe I’m not seeing the obvious, but is there a kind of “step” with a for
loop that’s possible (specifically w/ lists). I have a list like so: (x1 y1 x2 y2 ...)
and I’d like to iterate over the pairs of x/y’s. I’d be fine with something like:
(for ([x lst #:step cddr]
[y (cdr lst) #:step cddr])
...)
But I was hoping there might be another nice way to do it, too?

I think, for/fold is the closest.

eh, recursion it is then :wink:

There’s probably a way to make a sequence do that

Yeah, you could make your own in-list++
or whatever to do that

There’s in-slice
to group the elements. You need to manually extract x
and y
, though. https://docs.racket-lang.org/reference/sequences.html#%28def._%28%28lib._racket%2Fsequence..rkt%29._in-slice%29%29

Ah, that’s nice. Thanks

Here’s a sketch of doing it with streams #lang racket
(define mylst
'(x0 y0 x1 y1 x2 y2))
;; eo is a garbage name
(define (eo s next)
(cond
[(stream-empty? s) s]
[else
(stream-cons (stream-first s)
(eo (next s) next))]))
(define (stream-cddr s)
(stream-rest (stream-rest s)))
(for/list ([x (eo mylst stream-cddr)]
[y (eo (cdr mylst) stream-cddr)])
(cons x y))

I bet @notjack has a solution ;-)

Maybe it will use … transducers?!?!

:stuck_out_tongue:

I guess one could throw in an [n (in-naturals)] together within an #:when (even? n).

Hrm, using an arbitrary “step” function is a bit of a problem, since it makes it difficult to determine (efficiently) when you’re at the last position of the sequence.

in-slice
is how I do that usually :p

Yeah, that’s fine if you want consecutive elements. @massung’s idea would be more general than that.

the in-slice worked okay. It kinda sucks creating a new list, just to deconstruct it again to get the elements I care about.
WRT streams, recursive functions, etc. Yeah, I could come up with my own solutions easily enough. I was just hoping that there was something already built-in I could leverage.

I always hate that in scheme (car null)
and (cdr null)
end up being errors unlike CL. But there are benefits to it as well.

It’s frustrating implementing certain algorithms that have to begin with checking if the list is empty, or - even worse - having to check lengths (e.g. for take/drop, etc.).
Hence the hope for for
and a possible #:step
being nice and handling it for me :wink:

Yeah, match
can be good in those situations, though not necessarily in combination with for
, e.g.: #lang racket/base
(require racket/match)
(define input '(a 1 b 2 c 3 d 4 e 5 f 6))
(let loop ([xs input])
(match xs
[(list* x y xs) (cons (cons x y) (loop xs))]
[(list) null]
[_ (error "input doesn't have an even number of elements")]))

This seems like it might be a bug, but perhaps I’m misunderstanding

> (for ([(a b) (in-producer (const #f) (const #t))]) (void))
result arity mismatch;
expected number of values not received
expected: 2
received: 1
in: local-binding form
arguments...:
#f
context...:
/Applications/Racket v8.0/collects/racket/repl.rkt:11:26

In other words, I construct a sequence using in-producer
which never contains any elements.

Yet for
somehow detects that (all none of) those elements aren’t multi-valued

@pavpanchekha Are you using (const #t)
as the stop value here?

Oh sure — it’s a stop predicate.

Yeah, that’s the stop predicate

~Looking at the source, it appears to be using procedure-arity
to special-case the 1 value case.~

But that’s the stop code, which isn’t what’s causing this…

Well, okay, in the macro stepper, I can see that we get: (let-values ([(a b) (#%app producer*)])
(if (#%app not (#%app stop? a b))
[...]
So, it’s trying to bind two values, based on your binding syntax, before it tries to pass the results to the stop predicate.
I don’t know — based on the description of for
in the docs, I wouldn’t expect an error here, but I’m not what an efficient implementation that avoided the error would look like.

Could be nice to zip your original data instead, so you have ((x0 y0) (x1 y1) …)

I think it’s possible to create a new API that avoids creating an intermediate list and binds multiple elements at the same time. However, I wonder what should the API do if there are not enough elements left in the sequence.

This is the kind of thing that generic collection interfaces would help with, if we had them

https://docs.racket-lang.org/graphite-tutorial/index.html does this look odd for you all? the images towards the end are decidedly stretched out and not even the result of the code. could be my browser cache

what I’m talking about — this isn’t even the result of the shown code


I saw this

huh. it’s my cache, then

that’s the intended result

that’s the old pict_10.png — an image got removed from the tutorial and my browser cache must be displaying the old versions and shifting everything after the removal upwards

which is deeply annoying. oh well

In the case where the list’s length is n and you want to bind k elements at the same time but (n mod k > 0) there are two alternatives (at least in my eyes): • ignore the final (n mod k) elements entirely which is similar to the strategy of zip
from Racket’s list-util
OR • bind the final (n mod k) values to variables and leave the remaining variables bound to some default value. This would achieve the same result as padding the end of the list with (k - (n mod k)) copies of the default value before running it through the for
I personally find the first alternative more intuitive

I’ve been noticing read-compiled-linklet
every time I build Racket from source. E.g.,
raco setup: bootstrapping from source...
read-compiled-linklet: version mismatch expected: "8.1.0.6" found: "8.1.0.2" in: /Users/sorawee/projects/racket/racket/collects/compiler/private/compiled/cm-minimal_rkt.zo
raco setup: version: 8.1.0.6
raco setup: platform: aarch64-macosx [cs]
...
Everything works fine though. Is this something that should be worried?