Re: New member
Mabry Tyson <Tyson <at> AI.SRI.COM>
2005-04-16 03:13:51 GMT
FYI, the Common-Lisp <at> AI.SRI.COM list has been quite quiet over the past
several (or many) years. It was used much more in the days leading up
to the adoption of ANSI Common Lisp standard.
Since you're new to Lisp, I'll mention a few things regarding the code
you wrote.
Obviously in any language one can write a program whose running time is
inefficient. Your program is one of that class. But that's not bad in
and of itself. I've always felt we want to be efficient in our use of
people (both code writers and the users of the program), not computers.
A single-use program should be judged by how quickly it can be used,
from the start of writing to the end of its use. In that sense, your
program is efficient. But I wouldn't want to compute the primality of
any large Mersenne primes with it!
Given that, I'll comment about the code with regards to the code being
used more than once. There are those that have written text books that
have given more thought to this than me. I'm just a long-time user.
An issue with programming is the clarity of the program. Having
meaningful names helps, but one needs comments! Chunking the code
into meaningful functions is always important. For instance you could
have considered creating a function (defun DIVISIBLE-BY-P (product
factor) (zerop (mod product factor))). Having clean code (ie,
avoiding "(not ())" ) is a good idea while avoiding more complicated or
convoluted code (for instance, "(and foo ...)" is equivalent to "(if
(not (null foo)) foo ...)" but might confuse someone into thinking the
"(and ... )" expression return T or NIL when in fact it returns
something else. But we all do those short cuts.
[A convention from early days of lisp is using "-P" (for predicate) as a
suffix to a function name indicating that the function was a boolean
Predicate function. For instance, I would have named your function
PRIME-P rather than PRIME. I would use PRIME for some sort of action
such as PRIME-PUMP. That also brings up the issue of <verb>-<noun>
name formats versus <noun>-<method> name formats. One might name a
function as WRITE-CHECK, but if you're writing a number of such
functions for checks, money orders, etc, you might use CHECK-WRITE,
CHECK-DEPOSIT, CREDIT-CARD-CHARGE, .... Whatever you do, be
consistent. Did you notice that CHECK-DEPOSIT is ambiguous? ]
Anything one can do to let the next person (or even the same person!)
who looks at the code to better understand it is a good thing.
Consistent naming of functions by type; consistent ordering/naming of
arguments or variables; use of comments to explain the code; use of
declarations to indicate and test the arguments; use of error trapping;
testing of the code; etc. etc.
ALWAYS test the input from the user -- in this case, the arg of PRIME.
What should happen if the user asked for (prime NIL)? He will get some
error that he won't understand without looking at the code. What if he
asked for (prime 3.0)? Worse yet, what if he asked for (prime 3.1) or
(prime -5)??? What about (prime 0) or (prime 1)?
With bignums, Lisp can handle arbitrarily big numbers, but that doesn't
mean that the code can. Depending upon the optimizations of the
compiler, there will be some (actually an infinite number) large integer
argument to PRIME that will cause the system to fail (when it recurses
too deeply for the computer and Lisp you're running it on). You may
not have an easy way to know the actual value of that bound. You could
test for an arbittrary bound, or you could use CL's error trapping
system to detect an error.
Declarations of the types of arguments and other variables can help the
compiler produce faster code (perhaps at the expense of debugging, but
you've already been warned about testing the input and trapping errors)
as well as indicate to the next person what you intended the code to
do. Adding tests (eg, ASSERT) or other debugging statements,
especially during development will help the next person understand where
the code went wrong.
But, building "perfect" code takes effort and time that might be better
spent doing other things. For the code you wrote, it might be better
to, say, investigate other ways to be more efficient (if your testing
integers less than 10^9) or entirely different mechanisms (if testing
integers greater than 10^100), or maybe swapping space for speed (if
you're only testing integers less than 1000 but doing this often, it
might be better to use table lookup).
A lot of us write Lisp code for efforts that are more than just
one-time-use programs but less than productized used-by-the-average-joe
programs. Lisp is our language of choice for many reasons, some better
than others. As a researcher, I am always exploring ideas. Lisp gives
me the incremental capability to design the code as I better understand
the issues and to investigate what is happening in the middle of
execution. It gives me the debugging that I need for less-than-perfect
code. Lisp gives me the power to deal withh the unknown. Lisp is
efficient enough for every problem I've had to tackle.