[racket] This is too clumsy. Is there a better way?
On Jul 13, 2012, at 9:02 AM, Rouben Rostamian wrote:
> The function `all-lower-case?' defined below takes a string and
> returns #f if the string has at least one uppercase alphabetic
> character, else returns #t.
>
> Examples:
> (all-lower-case? "asdf12#@") => #t
> (all-lower-case? "asDf12#@") => #f
Then a better name would be no-upper-case? . I would expect (all-lower-case? "asdf12#@") to return false.
> Here is how I have written it:
>
> (define (all-lower-case? str)
> (not (memq #t
> (map (lambda (i)
> (if (and (char-alphabetic? i) (char-upper-case? i))
> #t #f))
> (string->list str)))))
For starters, I would replace
(if (and (char-alphabetic? i) (char-upper-case? i))
#t #f)
with the logically equivalent
(and (char-alphabetic? i) (char-upper-case? i))
(As a general rule of thumb, Boolean-valued functions are usually shorter and simpler if you write them WITHOUT conditionals.)
Second, since char-upper-case? is a subset of char-alphabetic?, you can simplify this further to
(char-upper-case? i)
which is just a single function, so you can now drop the "lambda" and just say
(map char-upper-case? ...)
You can also replace
(memq #t (map F L))
with
(ormap F L)
So the new definition is
(define (no-upper-case? str)
(not (ormap char-upper-case? (string->list str))))
> This looks rather clumsy to me. I am converting the string into
> a list of characters, then I check the case of each character
> and issue the requisite verdict.
We're still doing the exact same thing, but in a whole lot less code -- indeed, the code is very nearly a rewording of the purpose statement. As a bonus, it's also more efficient, since "ormap" does short-circuit evaluation: as soon as it finds an upper-case letter, it stops without looking at the rest of the string.
Another, weirder and less efficient but even shorter, definition is
(define (no-upper-case? str)
(string=? str (string-downcase str)))
Stephen Bloch
sbloch at adelphi.edu