This chapter describes how together with Chez Scheme’s resident random-number generator, let-expressions make it clearer how to write unit-test procedures.
Chez Scheme’s predefined procedure random, when applied to a positive integer n, returns a random non-negative integer smaller than n:
> (random 5)
4
> (random 5)
0
> (random 5)
0
> (random 5)
3
> (random 5)
4
> (random 5)
1
> (random 5)
3
>
In all cases, the results of evaluating (random 5) range between 0 and 4. In particular, they range between 0 and 1 if we evaluate (random 2), as if we were flipping a coin.
Whatever.—popular saying
Implement a generator of random lowercase characters.
Hint: Use the resident procedure char->integer and its left inverse integer->char that respectively convert a character into its ASCII code and vice versa.
Bong-sun: Let me see. First, char->integer and integer->char:
> (integer->char (char->integer #\a))
#\a
> (integer->char (char->integer #\z))
#\z
>
Dana: Actually, we might as well look at the ASCII codes of #\a and of #\z:
> (char->integer #\a)
97
> (char->integer #\z)
122
>
Alfrothul: OK. So 97, 98, etc. are the ASCII codes of #\a, #\b, etc.
Bong-sun: Let me check:
> (- (char->integer #\z) (char->integer #\a))
25
>
Dana: Right. There are 26 letters of the alphabet.
Bong-sun: So if we add a random number between 0 and 24 to the ASCII code of #\a, we get the ASCII code of a lowercase character.
Alfrothul: And if we convert this ASCII code to a character, this character is lowercase:
(define random-char-lowercase
(lambda ()
(integer->char (+ (char->integer #\a) (random 26)))))
Pablito: Let me try, let me try:
> (random-char-lowercase)
#\i
> (random-char-lowercase)
#\x
> (random-char-lowercase)
#\f
> (random-char-lowercase)
#\b
>
Implement a generator of random uppercase characters.
Bong-sun: Aha!
The fourth wall: Ahem.
Bong-sun: Oops. Sorry, Fourth Wall. Can we have an interlude now?
The fourth wall: Sure thing.
Bong-sun: Thanks.
Bong-sun: Aha!
The fourth wall: OK, I am curious. Aha, what?
Bong-sun: Now we can more conveniently test properties in our unit tests.
The fourth wall: Pray elaborate.
Bong-sun: It’s really simple. We can name random numbers locally, and then test computations that involves these random numbers. For example, consider a candidate procedure that allegedly implements the addition function for non-negative integers. We can test whether it is commutative and associative:
(define unit-tests-for-add
(lambda (candidate)
(and (let ([x (random 100)]
[y (random 100)])
(= (candidate x y)
(candidate y x)))
(let ([x (random 100)]
[y (random 100)]
[z (random 100)])
(= (candidate (candidate x y) z)
(candidate x (candidate y z)))))))
Created [13 Sep 2025]