[plt-scheme] horay(?) to me!

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Mon Jun 12 09:10:49 EDT 2006

>> Small comments on the toy code:
>>> (let loop ((running #t))
>>> (let ((r (random 20)))
>>> 	(set! running (< r 17))
>> The *running* variable here doesn't have to be part of the loop's
>> iteration.  In fact, the code recomputes it anyway!  A slightly cleaner
>> version of the above might look something like this:
>> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>> (let loop ()
>>   (let* ([r (random 20)]
>>          [running (< r 17)])
>>     ...))
>> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>> We use the let* form to tell people reading the code that *running* will
>> be influenced by *r*.  We can avoid the use of set! altogether.
> I was using a lot of (let* and recently have tried only using (let instead.

Hi Mike,

Although we can do the above with lets alone:

     (let loop()
       (let ((r (random 20)))
         (let ((running (< r 17)))

this starts feeling a little too cramped.  I do think using let* in the 
context above is appropriate.

>>> 	        (thread
>>> 			  (eval
>>> 			  `(lambda () (sleep (random 4))
>>>                                    (printf "thread count=~a~%" ,r)))))
>>> 	;(sleep 2)
>> The eval/quasiquotation here is unnecessary, but you know that already.
>> *wink*
> Ok, here you lost me. I am trying to get the value of 'r' into the 
> thread for delayed printing. The quasiquote is the only way I found to 
> make this happen. Please, do tell, how is it unnecessary? That part I've 
> not learned yet. :(

Oh!  Ok, good, glad we're talking about this then.

But just checking: are you using 'How to Design Programs'?


If you're looking at HTDP, take a closer look at the chapters starting 
from Part IV:


Sections 20 and 21 are especially relevant here.  I'd strongly recommend 
reading those sections, because they really help out a lot.

In Scheme, functions can remember the variables in their scope.  For 

;; make-adder: number -> (number -> number)
;; Given n, returns a new function that adds n to its argument.
(define (make-adder n)
   (lambda (x)
     (+ n x)))

When we run make-adder:

> (make-adder 42)

we get back a function.  That function, created in a context where n is 
bound to 42, will remember that binding:

> (define f (make-adder 42))
> (f 17)

Note that this is not the same as global variables in other languages! 
It's perfectly ok to make different, independent adder instances:

> (define inc1 (make-adder 1))
> (define inc2 (make-adder 2))
> (define inc3 (make-adder 3))
> (define (test x)
     (list (inc1 x) (inc2 x) (inc3 x)))
> (test 5)
(6 7 8)
> (test 6)
(7 8 9)

Does this make sense so far?

> See, from the other languages I've used I much prefer to have a (while
> than a (let loop. I can easily deal with the (if, though from PERL I would
> like to have an (unless.

*unless* is in there.


About *while*: Scheme is a fluid language.  You can have your while cake 
and eat it too.  Although *while* may not be hardcoded into the language, 
we can just add it in:

> (define-syntax while
     (syntax-rules ()
       ((_ test body ...)
        (let loop ()
          (when test
            body ...

This snippet tells Scheme how to deal with while loops: it defines a 
syntactic rule that translates while loop constructs into simpler --- but 
equivalent --- code.  Once we type out the above (or reuse it from a 
library), we can start using while loops just like in other languages:

> (define (wait-for-hello)
     (define my-input (read-line))
     (while (not (equal? my-input "hello"))
       (printf "try again~n")
       (set! my-input (read-line))))
> (wait-for-hello)
try again
try again

That being said, the above code is a bit clumsy: we can do perfectly well 
with a simple recursive call here:

> (define (wait-for-hello)
     (define my-input (read-line))
     (unless (equal? my-input "hello")
       (printf "try again~n")

while loops are very much tied to imperative set!-ish code; I use it much 
less than I had expected when I started using Scheme.  But if we do need 
to use *while*, we can use Jen Soegaard's *control* package from the 
PLaneT package repository.  See:


Best of wishes!

Posted on the users mailing list.