How do you write a function (case? s) that returns the 'upper if the
characters in the string s are all upper case, 'lower if the characters are
all lower case, and 'mixed if there are some lower case and some upper case
letters?
In article <·····························@68.1.17.6>, Bldahdad wrote:
>How do you write a function (case? s) that returns the 'upper if the
>characters in the string s are all upper case, 'lower if the characters are
>all lower case, and 'mixed if there are some lower case and some upper case
>letters?
This is a good opportunity to expore the nice library of Common Lisp,
rather than drop down to character-by-character processing.
(defun case? (string)
(cond
((every #'lower-case-p string) 'lower)
((notevery #'upper-case-p string) 'mixed)
(t 'upper)))
Bad name for the function, though, IMHO. The question mark suffix is
a convention from Scheme, and other languages, for denoting predicates.
In Lisp, the convention for predicates is to use a P or -P suffix,
but it's still a bad idea to use a ? suffix for non-predicates.
A function that classifies input into three or more buckets is not
a predicate; a predicate is boolean-valued. I would call it case-classify
or something.
Any more homework you want people to do for you?
In article <·······················@news3.calgary.shaw.ca>, ···@ashi.footprints.net wrote:
> In article <·····························@68.1.17.6>, Bldahdad wrote:
> >How do you write a function (case? s) that returns the 'upper if the
> >characters in the string s are all upper case, 'lower if the characters are
> >all lower case, and 'mixed if there are some lower case and some upper case
> >letters?
>
> This is a good opportunity to expore the nice library of Common Lisp,
> rather than drop down to character-by-character processing.
>
> (defun case? (string)
> (cond
> ((every #'lower-case-p string) 'lower)
> ((notevery #'upper-case-p string) 'mixed)
> (t 'upper)))
I think you got it wrong.
? (case? "LISP QUESTION1")
MIXED
(defun case? (string)
(cond
((every #'upper-case-p string) 'upper)
((every #'lower-case-p string) 'lower)
((and (some #'upper-case-p string)
(some #'lower-case-p string))
'mixed)
(t (error "You lose."))))
abe
--
<keke at mac com>
····@ma.ccom (Takehiko Abe) writes:
Is this homework? I don't recall being told. Homework should not be
presented to this newsgroup without identifying it as such.
> In article <·······················@news3.calgary.shaw.ca>, ···@ashi.footprints.net wrote:
>
> > In article <·····························@68.1.17.6>, Bldahdad wrote:
> > >How do you write a function (case? s) that returns the 'upper if the
> > >characters in the string s are all upper case, 'lower if the characters are
> > >all lower case, and 'mixed if there are some lower case and some upper case
> > >letters?
> >
> > This is a good opportunity to expore the nice library of Common Lisp,
> > rather than drop down to character-by-character processing.
And maybe have half a hope that the person hasn't been given the direct
answer to a homework problem.
> > (defun case? (string)
> > (cond
> > ((every #'lower-case-p string) 'lower)
> > ((notevery #'upper-case-p string) 'mixed)
> > (t 'upper)))
>
> I think you got it wrong.
>
> ? (case? "LISP QUESTION1")
> MIXED
>
> (defun case? (string)
> (cond
If you're going to insist on pure-letters, then you maybe want to start with:
((notevery #'both-case-p string) 'garbage)
Wow. I never saw a use of NOTEVERY. I almost missed my chance and wrote
the probably less efficient:
((some (complement #'both-case-p) string) 'garbage)
If you don't do a "guard test" like this, then you'll need some of the
other changes I suggest below...
> ((every #'upper-case-p string) 'upper)
I might prefer (complement #'lower-case-p) here, so that both F and $
count as upper for this situation. Though this would have the problem
that '$$$ counts as all upper. Certainly it is not all lower, nor is
it mixed.
> ((every #'lower-case-p string) 'lower)
and (complement #'upper-case-p) here, so that both f and $ count as
lowercase.
> ((and (some #'upper-case-p string)
> (some #'lower-case-p string))
If you make my suggested changes above, then T is a fine test here.
If you don't, then you're insisting on all letters as input and it
probably makes sense to require the same here. In this case,
(every #'both-case-p string)
would be more rational test here.
> 'mixed)
> (t (error "You lose."))))
I might just return 'garbage here rather than signal an error, since
that leaves it to clients of this function to determine whether in fact
that was an error...
And it's a subtle point, but if you are going to signal an error,
I'd make the error message more informative. Something like:
(error "~S was given input that it was not specified to handle.~
~%Please report this as a bug."
'case?)
Though if foo1 counts as mixed, that's kind of weird, since it's not a mix
of the other two possible return values. All in all, had I written it, I
might have written:
(defun case? (string)
(cond ((some #'upper-case-p string)
(if (some #'lower-case-p string)
'mixed ;but maybe also non-alpha
'upper)) ;but maybe also non-alpha
((some #'lower-case-p string)
'lower) ;but maybe also non-alpha
(t ;"" or all non-alpha
'garbage)))
or
(defun case? (string)
(cond ((notevery #'both-case-p string) 'garbage)
((some #'upper-case-p string)
(if (some #'lower-case-p string)
'mixed
'upper))
((some #'lower-case-p string)
'lower)
(t ;""
'none)))
If you wanted to be manic about efficiency, either the following, or better
still the equivalents with position-if and position-if-not open-coded
into loop in case the compiler isn't smart enough to do even that.
(Then again, this will be pessimal in clisp, which is byte-compiled and
prefers you to use standard operators rather than rolling your own.
Even in other implementations the savings may only be in the range of
25-50% ...) Certainly the loss of readability is substantial and you'd
have to test it a lot more thoroughly to be sure it was right...
(defun case? (string)
(if (= (length string) 0) 'none
(let ((ch0 (char string 0)))
(macrolet ((check-consistency (test fliptest result)
`(let ((pos (position-if-not #',test string :start 1)))
(if (not pos) ',result
(if (,fliptest (char string pos))
(if (position-if-not #'both-case-p string
:start 2)
'garbage
'mixed)
'garbage)))))
(cond ((upper-case-p ch0)
(check-consistency upper-case-p lower-case-p upper))
((lower-case-p ch0)
(check-consistency lower-case-p upper-case-p lower))
(t 'garbage))))))
In article <···············@shell01.TheWorld.com>, Kent M Pitman <······@world.std.com> wrote:
> > > (defun case? (string)
> > > (cond
> > > ((every #'lower-case-p string) 'lower)
> > > ((notevery #'upper-case-p string) 'mixed)
> > > (t 'upper)))
> >
> > I think you got it wrong.
> >
> > ? (case? "LISP QUESTION1")
> > MIXED
> >
> > (defun case? (string)
> > (cond
>
> If you're going to insist on pure-letters, then you maybe want to start with:
I don't insist on pure letters. The instruction says:
'upper if all the chars are upper case letters.
'lower if all lower.
'mixed if some are upper case and some are lower case.
> ((notevery #'both-case-p string) 'garbage)
So, I believe, for instance, "Lisp Question 1" should return 'mixed
instead of 'garbage.
> [...]
I'll study the rest tomorrow. Good night.
abe
--
<keke at mac com>
In article <·····················@solg4.keke.org>, Takehiko Abe wrote:
>In article <·······················@news3.calgary.shaw.ca>, ···@ashi.footprints.net wrote:
>
>> In article <·····························@68.1.17.6>, Bldahdad wrote:
>> >How do you write a function (case? s) that returns the 'upper if the
>> >characters in the string s are all upper case, 'lower if the characters are
>> >all lower case, and 'mixed if there are some lower case and some upper case
>> >letters?
>>
>> This is a good opportunity to expore the nice library of Common Lisp,
>> rather than drop down to character-by-character processing.
>>
>> (defun case? (string)
>> (cond
>> ((every #'lower-case-p string) 'lower)
>> ((notevery #'upper-case-p string) 'mixed)
>> (t 'upper)))
>
>I think you got it wrong.
>
>? (case? "LISP QUESTION1")
>MIXED
>
>(defun case? (string)
> (cond
> ((every #'upper-case-p string) 'upper)
> ((every #'lower-case-p string) 'lower)
> ((and (some #'upper-case-p string)
> (some #'lower-case-p string))
> 'mixed)
> (t (error "You lose."))))
What, there are other characters beside letters? Damn! ;)
Takehiko Abe wrote:
> In article <·······················@news3.calgary.shaw.ca>, ···@ashi.footprints.net wrote:
>
>
>>In article <·····························@68.1.17.6>, Bldahdad wrote:
>>
>>>How do you write a function (case? s) that returns the 'upper if the
>>>characters in the string s are all upper case, 'lower if the characters are
>>>all lower case, and 'mixed if there are some lower case and some upper case
>>>letters?
>>>
>>This is a good opportunity to expore the nice library of Common Lisp,
>>rather than drop down to character-by-character processing.
>>
>>(defun case? (string)
>> (cond
>> ((every #'lower-case-p string) 'lower)
>> ((notevery #'upper-case-p string) 'mixed)
>> (t 'upper)))
>>
>
> I think you got it wrong.
>
> ? (case? "LISP QUESTION1")
> MIXED
>
> (defun case? (string)
> (cond
> ((every #'upper-case-p string) 'upper)
> ((every #'lower-case-p string) 'lower)
> ((and (some #'upper-case-p string)
> (some #'lower-case-p string))
> 'mixed)
> (t (error "You lose."))))
>
> abe
>
>
The original statement of the problem says specifically ". . .'mixed if
there are some lower case and some upper case letters?". There are
clearly upper case letters in your example string "LISP QUESTION1",
however, which lower case letters does it contain? Your example should
trigger the error clause. The problem is that the specification is
ambiguous. It doesn't explain what behavior to expect for characters
without a case. There seems to be something wrong with your Lisp
implementation. Mine says that (both-case-p #\1) and (both-case-p
#\Space) return NIL.
David Sletten
In article <················@home.com>,
David Sletten wrote:
> Your example should trigger the error clause.
It signals an error -- "You lose." I admit that it's not
informative nor helpful.
> There seems to be something wrong with your Lisp implementation.
You seem to misunderstand something. My Lisp implementation is
fine.
How about this:
(defun case? (string)
(cond
((every #'upper-case-p string) 'upper)
((every #'lower-case-p string) 'lower)
((and (some #'upper-case-p string)
(some #'lower-case-p string))
'mixed)
(t (restart-case (error "You got ~S. Ask your instructor what to do."
string)
(specify-return-value (value)
:report "Specify a return value."
:interactive
(lambda ()
(format t "~&Value: ")
(list (read)))
value)))))
abe
--
<keke at mac com>
Takehiko Abe wrote:
>
> You seem to misunderstand something. My Lisp implementation is
> fine.
>
Yes, I did misunderstand something. In your initial response you wrote:
>
> I think you got it wrong.
>
> ? (case? "LISP QUESTION1")
> MIXED
>
> (defun case? (string)
> (cond
> ((every #'upper-case-p string) 'upper)
> ((every #'lower-case-p string) 'lower)
> ((and (some #'upper-case-p string)
> (some #'lower-case-p string))
> 'mixed)
> (t (error "You lose."))))
It was not evident that you were invoking the previous poster's function
and then defining your own. I thought you were displaying the output of
your version and then showing how you had defined it. However,
interpreting your post in the normal context of a Lisp session (where
your function could not be invoked before it was defined) makes sense
now. You were demonstrating that his version produced MIXED given "LISP
QUESTION1", and you did not demonstrate your own version, which of
course is correct under a certain interpretation of the problem. Gomen
nasai.
My point still stands though that the specification is ambiguous. It
does not say what to do when not all characters are upper case yet none
are lower case and vice versa.
David Sletten
In article <·····························@68.1.17.6>, Bldahdad
<····@blasdh.com> wrote:
> How do you write a function (case? s) that returns the 'upper if the
> characters in the string s are all upper case, 'lower if the characters
> are
> all lower case, and 'mixed if there are some lower case and some upper
> case
> letters?
That function is incompletely specified, and looks like a homework
question. So here's a solution in a closely related language (my choice
of which won't be any surprise to regular reasders :-)):
define function case?(s)
select
every?(uppercase?, s) => #upper;
every?(lowercase?, s) => #lower;
otherwise => #mixed;
end
end
-- Bruce