Re: New member
Mabry Tyson <[email protected]> Fri, 15 Apr 2005 20:13:51 -0700
| Newsgroups | gmane.lisp.common-lisp |
|---|---|
| Message-ID | <[email protected]> |
FYI, the [email protected] 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.