[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'?

     http://www.htdp.org/

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

http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-24.html#node_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 
example:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 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)
#<procedure>
;;;;;;

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)
59
;;;;;;


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.

http://download.plt-scheme.org/doc/301/html/mzscheme/mzscheme-Z-H-2.html#node_idx_48

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 ...
            (loop))))))
;;;;;;

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
foo
try again
hello
>
;;;;;;;


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")
       (wait-for-hello)))
;;;;;;


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:

     http://planet.plt-scheme.org/#control.plt1.0


Best of wishes!


Posted on the users mailing list.