[racket] a little macro exercise
On Fri, Oct 8, 2010 at 10:04 PM, Shriram Krishnamurthi <sk at cs.brown.edu> wrote:
> One of my students recently sent me this needless email message:
>
>> Well, how would you do switch fall-through in Scheme? Could you
>> write a version of the case statement that does that?
>
> Since the honor of Racket was at stake (yes, we can have all the same
> stupid features the scripting languages have!)
and stupid it is! from http://en.wikipedia.org/wiki/Switch_statement :
switch (n) {
case 0:
puts("You typed zero.");
break;
case 1:
case 4:
case 9:
puts("n is a perfect square.");
break;
case 2:
puts("n is an even number.");
case 3:
case 5:
case 7:
puts("n is a prime number.");
break;
case 6:
case 8:
puts("n is an even number.");
break;
default:
puts("Only single-digit numbers are allowed.");
break;
}
in the case of 2, it prints both "n is an even number." and "n is a
prime number." which is fine for 2, but may feel like a bug most
n00bs, since it looks like the last statement should apply only to the
"labels" 3,5 and 7. Plus, for 4 it prints "n is a perfect square.",
but not "n is an even number.", which looks like it was overlooked by
the developer. Fall-through is far less useful than one might think,
specially in light of a supposed canonical, instructive and short
example being flawed -- you can only imagine one in production use!
I'd rather try to persuade the n00b on why fall-through is bad (many
sources of subtle and hard-to-identify bugs, as even the wikipedia
article notices) and instead educate him on the fine art of How to
Design Programs... ;)
my take on plain ol' scheme for the above switch mess:
(define (properties n)
(if (> n 9) "Only single-digit numbers are allowed."
(fold '() (lambda (i o) (if (memq n (car i)) (cons (cdr i) o) o))
`(((0) . "You typed zero.")
((1 4 9) . "n is a perfect square.")
((2 4 6 8) . "n is an even number.")
((2 3 5 7) . "n is a prime number.")))))
; given this non-tail-recursive fold
(define (fold init f ls) (if (null? ls) init (f (car ls) (fold init f
(cdr ls)))))
; testing
(map properties '(0 1 2 3 4 5 6 7 8 9 10))
Plus, it's shorter if you take fold for granted (and you should).