Home > Enterprise >  For Loop Construction Turned Functional
For Loop Construction Turned Functional

Time:02-13

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)))
  • Related