Working code
Here is how I would do it:
(defun ask-and-read (prompt)
"Prompt the user and read his input."
(princ prompt *query-io*)
(force-output *query-io*) ; flush the buffers
(let ((*read-eval* nil)) ; close the security hole
(read *query-io*)))
(defun request-object (prompt predicate)
"Ask the user for an object using prompt.
Only accept data which satisfies the predicate."
(loop
for object = (ask-and-read prompt)
when (funcall predicate object)
return object
do (format *query-io* "Alas, ~S (~S) does not satisfy ~S, please try again~%"
object (type-of object) predicate)))
Example:
> (request-object "Enter an integer: " #'integerp)
Enter an integer: 4.6
Alas, 4.6 (SINGLE-FLOAT) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: 5/7
Alas, 5/7 (RATIO) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: asdf
Alas, ASDF (SYMBOL) does not satisfy #<SYSTEM-FUNCTION INTEGERP>, please try again
Enter an integer: 7
==> 7
> (request-object "Enter a real: " #'realp)
Enter a real: 4.5
==> 4.5
> (request-object "Enter a real: " #'realp)
Enter a real: 5/8
==> 5/8
> (request-object "Enter a real: " #'realp)
Enter a real: "sdf"
Alas, "sdf" ((SIMPLE-BASE-STRING 3)) does not satisfy #<SYSTEM-FUNCTION REALP>, please try again
Enter a real: 8
==> 8
Please see the documentation for the facilities I used:
Your mistakes
Code formatting
Your code is unreadable because you have incorrect indentation.
Lispers do not count parens - this is the job for compilers and editors.
We look at indentation.
Please do yourself a favor and use Emacs - it will indent the code for you and you will often see your errors yourself.
Defvar is a top-level form
First of all, defvar is a top-level form which is used to define global variables, not set them.
Subsequent calls do not change the value:
(defvar *abc* 1)
*abc*
==> 1
(defvar *abc* 10)
*abc*
==> 1 ; not 10!
Use setq to set variable.
Prefer local variables to global variables
While Lisp does allow global variables, the predominant programming
style in Lisp is the functional style: every function receives its
"input" data as arguments and returns its "output" data as values.
To achieve functional style, prefer a local to a global variable.
You create local variables through let or
let* or, in loop, see
Local Variable Initializations.
Cond and When have very specific syntax
You have extra parens and 1(?!) in your cond and when forms.
Remember, parens are meaningful in Lisp.
Security first!
Binding *read-eval* to nil
before read is necessary to
avoid a nuclear war if a user enters #.(launch-nuclear-missiles)
in response to your prompt, because normally read evaluates whatever
comes after #..