I am currently learning Racket and want to do the following simple task: Construct a list which contains all tuples (i,j) : Int * Int with 0 <= i < N and 0 <= j < M.
In, let's say Python, I would immediately know how to approach this, by using for loops:
# Not using any modules on purpose here
a = []
for i in range(5):
for j in range(6):
a.append((i,j))
But I have trouble doing this in Racket. By now I have found a solution which replicates the for-loop approach by using a recursively defined function which for a : A and f : Int -> A -> A satisfies the equations
for 0 a f = (f 0) a
for n a f = for (n-1) ( (f n) a ) f
which results in a chain of applications: for n a f = ( (f 0) ∘ ... ∘ (f n) )(a). (By f ∘ g I mean composition of f and g). So first f n is applied to a, then f (n - 1) to the result of that, etc.
Given I basically want to do something like ((f 0 0) ∘ (f 0 1) ∘ ... ∘ (f N M)) (a), it can be split up as:
(((f 0 0) ... (f 0 M)) ∘ ... ∘ ((f N 0) ... (f N M))) (a)
= ((λz. for M z (f 0)) ∘ ... ∘ (λz. for M z (f N))) (a)
= for N a (λi z. for M z (f i))
Which then translates to the following Racket code:
(define (for n a f) ;; (for n '() cons) = range(n) = (0 1 ... n-1)
(if (< 0 n)
(for (- n 1) (f (- n 1) a) f)
a))
(define a '())
(define (append i j x) (cons (cons i j) x))
(for 5 a (λ(i x)
(for 6 x (λ(j y)
(append i j y)))))
The answer produces the desired result and is at least nice regarding that it is obvious how to extend this construction with any number of additional loops.
But I am still wondering whether there isn't a neater functional way to do this.
I'm happy with any answer that does or does not use functions which might already be present in some library and which I have simply missed so far.
You are probably looking for for*/list:
(for*/list ([i (range 5)]
[j (range 6)])
(list i j))
See also Racket guide for Iterations and Comprehensions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With