Im not as familiar with the sequence or stream apis, but why the trip through streams and stream first?
(The answer to my question is because of how in-slice
works; but I found two other ways to do it. If you put in-cycle
at the top of the threading like you did originally, my first option is slightly shorter because it doesn’t need stream-first
.) (~> '(A B)
in-cycle
sequence->stream
(stream-take 9)
sequence->list)
;;=> '(A B A B A B A B A)
or (for/list ([ab (in-cycle '(A B))]
[n (in-naturals)])
#:break (>= n 9)
ab)
;;=> '(A B A B A B A B A)
You could even use (in-range 9) there
I needed the first one though. I got this working (~> (in-cycle '(A B))
(in-slice 9 _)
(sequence-ref _ 0))
really surprising I couldn’t find a sequence-take
(even though sequence-tail
exists) nor a sequence-first
. I think that’s the reason I assumed data/collection
was a popular go-to since it makes all that stuff “just work”, but since it conflicts with typed/racket, I just won’t use it and stick to the sequence and stream stuff
Next question - what is the equivalent of a zip
function which can combine multiple sequences? Specifically, map
doesn’t work if the input sequences are not of equal length, and I don’t want to make an intermediate list
zipShortest
can be done roughly by using for
forms
huh.. ok I was looking at those docs now but I don’t see how? do you provide multiple for-clause
s?
Yes:
(for/list ([x '(1 2 3)] [y '(1 2 3 4)])
(list x y))
;=> '((1 1) (2 2) (3 3))
oh, interesting, so it does shortest already, cool
hmm…so actually trying to write zip-shortest
I can’t quite figure it out. The function I want would be varadic same as map
so you can do things like (zip-shortest list lst1 lst2 lst3 lst4)
and you’d get back a list of lists each with 4 items in it.
I can write it with the for
form, but no clue how I would do it when the number of for-clause
s might vary depending on input
Actually… you asked that question :smile:
oooh…yeah would you look at that. Yea, I’ve been coming back to Racket to play with it every few months for 2 years now huh?
what would be the technique if I wanted to write that as a macro? would I have to dynamically generate variable names or is there a helper for that?
So, just want to make sure you understand the limitation of macros. You can definitely write zip-shortest
as a macro, but it means you can’t do:
(apply zip-shortest (list a b c))
any more (well, you actually can, but it essentially falls back to the solution in StackOverflow). Is this what you really want?
Dynamically generate n
variable names can be done by using a function named generate-temporaries
.
Yeah, just for learning’s sake. I get that it’s not a spectacular way to do stuff
Though if I understand it correctly, if it was a macro then it could theoretically be pulled into another typed/racket package and still work even without me providing any annotations, right? Since by the time the type checker runs it will have been expanded?
@samth would be able to answer that better than me, but my impression is that this is incorrect: macro usually complicates type checking.
FYI, here’s what the macro would look like:
#lang racket
(require syntax/parse/define)
(define-syntax-parse-rule (zip-shortest xs ...)
#:with (x ...) (generate-temporaries (attribute xs))
(for/list ([x (in-list xs)] ...)
(list x ...)))
(zip-shortest (list 1 2 3)
(list 1 2 3 4)
(list 1 2 3 4 5))
ooh cool, thanks