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 = a
for n a f = for (n-1) ( (f \, n) a ) f
which results in a chain of applications: for n x f = (f0) o ... o (fn)(a)
. (By f o 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 to something like (f 0 0) o (f 0 1) o ... o (f N M) (a)
this can be split up as:
((f 0 0) ... (f 0 M)) o ... o ((f N 0) ... (f N M)) (a)
= (λz. for M z (f 0)) o ... o (λz. for M z (f N)) (a)
= (λy. for N y (λi z. for M z (f i))) (a)
Which then translates to the following Racket code:
(define (for n x f)
(if (<= 0 n)
(for (- n 1) (f n x) f)
x))
(define a '())
(define (append i j x) (cons (cons i j) x))
((λ(x)
(for 5 x (λ(i x)
(for 6 x (λ(j x)
(append i j x)))))) a)
The answer produces the desired result and is at least nice regarding that it is obvious how the 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.
CodePudding user response:
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.
CodePudding user response:
The for*/$@!
forms are compact, but Scheme ("Programming languages should be designed not by piling feature on top of feature...") is still there:
(define (range-pairs m n) ;; Nat Nat -> (Listof (Cons Nat Nat))
;; produce (range m) ⨯ (range n)
(do ([i (sub1 m) (sub1 i)]
[a '() (do ([j (sub1 n) (sub1 j)]
[a a (cons (cons i j) a)])
((negative? j) a))])
((negative? i) a)))