It would be easier to give suggestions if you could share some of your non-working attempts, so we could suggest changes for you to consider.
Since you mentioned apply, one thing I noticed when working out a solution for myself was that the somewhat “magic” way multiple arguments are transformed into a list adds an extra dimension to think about. It might simplify things to break down the problem this way:
SPOILER: Here is one solution—but do try working it out yourself.
```
#lang racket
(define (zip . lsts)
(if (ormap null? lsts)
null
(cons (map car lsts)
(apply zip (map cdr lsts)))))
```
It would be easier to give suggestions if you could share some of your non-working attempts, so we could suggest changes for you to consider.
Having come from imperative langugages I started using the for loops when I couldn't figure out the apply with recursion. Here's the non working imperative version. for/list was really close to what I wanted so I figured I could somehow inject what I needed into it.
(define (variadic2 . in)
(define out empty)
(for ([z (in-range (length (car in)))])
(for ([x (in-range (length in))])
(append (list (list-ref (list-ref in x) z)) out )))
out)
I deleted my recursive attempts, but will try again.
One problem with this code is that Racket's append is very different from Python's append. In Python, x.append(y) mutates list x by inserting the contents of list y at the end, returning None. In Racket, lists are immutable, and (append x y) returns a new list containing the contents of x followed by the contents of y: it is a pure function, with no side-effects. That means your variadic2 will always return the initial out, i.e. empty: the for loops are just dead code.
Another thing to note is that list-ref is often a sign of poorly structured code, because lists are not random-access: list-ref must traverse from the beginning, taking O(n) time. That's all the more true when used in a pattern like:
(for ([x (in-range (length in))])
... (list-ref in x) ...)
which could be written instead as:
(for ([v (in-list in)])
... v ...)
It makes your code clearer to directly iterate through the elements of a sequence, rather than accessing them indirectly through an index, and in many cases it will perform better, too.
If you want a data structure that works more like Python lists, take a look at racket/treelist.