[plt-scheme] horay(?) to me!
>> 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!