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?
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.
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.
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.
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.
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))
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.
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