Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Do For Loops Work In Scheme?

I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why

 (define (bubblesort alist)
  ;; this is straightforward
  (define (swap-pass alist)
    (if (eq? (length alist) 1)
        alist
        (let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
          (if (> fst scnd)
              (cons scnd (swap-pass (cons fst rest)))
              (cons fst (swap-pass (cons scnd rest)))))))
  ; this is mysterious--what does the 'for' in the next line do?
  (let for ((times (length alist))
            (val alist))
    (if (> times 1)
        (for (- times 1) (swap-pass val))
        (swap-pass val))))

I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.

Any thoughts on what's going on here?

like image 893
Pseudo-Gorgias Avatar asked Feb 16 '12 14:02

Pseudo-Gorgias


People also ask

Is there a for loop in Scheme?

Scheme is very odd in one sense, it has no expressions designed for looping, repeating or otherwise doing something more than once at a general level.

HOW DO FOR loops in for loops work?

A "For" Loop is used to repeat a specific block of code a known number of times. For example, if we want to check the grade of every student in the class, we loop from 1 to that number. When the number of times is not known before hand, we use a "While" loop.

How does let work in Scheme?

In Scheme, you can use local variables pretty much the way you do in most languages. When you enter a let expression, the let variables will be bound and initialized with values. When you exit the let expression, those bindings will disappear.

What is begin in Scheme?

Scheme begin expressions aren't just code blocks, though, because they are expressions that return a value. A begin returns the value of the last expression in the sequence. For example, the begin expression above returns the value returned by the call to bar . The bodies of procedures work like begin s as well.


2 Answers

That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.

(let loop ((times 10))
   (if (= times 0)
     (display "stopped")
     (begin (display "still looping...")
            (loop (- times 1)))))

gets expanded to something like

(letrec ((loop (lambda (times)
                 (if (= times 0)
                   (display "stopped")
                   (begin (display "still looping...")
                          (loop (- times 1)))))))
  (loop 10))
like image 139
Fred Foo Avatar answered Nov 15 '22 06:11

Fred Foo


This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).

What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.

Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.

like image 36
Asumu Takikawa Avatar answered Nov 15 '22 05:11

Asumu Takikawa