AutoLISP Lesson #8 - LOOPING AutoLISP gives us some basic looping functions, which are quite useful, and as with everything else in lisp if we don't like what they gave us we can write our own. Looping functions repeat (repeat number exp ...) Evaluates each expression a given number of times. The number of times the loop operates is "num" times for each "exp". Number represents any positive integer. while (while testexp exp ...) Evaluates the "exp" while the "testexp" remains true. While evaluates "testexp" and if "testexp" is true it evaluates all expressions enclosed in the loop. It then reevaluates "testexp", if "testexp" is still true it goes through the loop again. This continues until "testexp" evaluates to nil. The repeating loop (repeat 5 The thing that limits the use of the repeat function is there are not many times you know how many times your going to need to go through the loop. Watch for the times you do know before hand, because repeat would be the cleanest way to deal with it. The while loop (while (this_is_true) The "testexp" can contain relational, as well as logical, operators. This operator must return a true or false value. As stated before a, "false" value in lisp is equivalent to "nil". If the "testexp" is found to be false when the loop is entered, the body of the loop is never executed. Controlling the loop There are two things you can do to keep out of trouble when writing loops. First minimize the number of factors that effect the loop. Keep it simple. Second treat the inside of the routine as if it were a function, keep as much control as possible outside the body of the loop. Be very clear about when the body of the function will execute. Don't make the reader have to look all through the loop to find out what makes it work. A loop should be another black box, like a function, the surrounding program may know the controls for the loop, but not the contents of the loop. When writing a loop put the code that initializes the loop directly in front of the loop. Keeping the initialization code close to the loop itself makes it easier to see how the loop works, and to make modifications later. If related statements are strewn throughout your program it will be very difficult to figure out later how it works. When you are writing the terminator for your loop, try to visualize every condition that will make the loop end. Beyond anything else we want our loop to end. Think through the nominal cases the boundary conditions, and every exceptional case you can think of. Writing a loop The best way to write loops is to write the loops in pseudo-code. Pseudo-code is a way of writing down what your code should be doing before you write the code. If you’re doing it right the pseudo-code will look like the finished code when your done, but will be in plain English ;while this is true Rather simplistic example but I think you get the point. What were trying for here is to get the feel of what your program will be doing. When we write the pseudo-code, we will write it using the comment markers for AutoLISP, that way when we are writing the code we can turn the pseudo-code into the comments for the loop. If we decide the loop is clear enough after we write it we can always delete the comments. Recursion In those cases where recursion is the best way to do something, there are a few things you should keep in mind while writing recursive functions. Make sure at some point the recursion stops. Check your function when your done to make sure you have left a path out of the recursive loop. What this means is that you should have a test as part of the function to break out of the loop when a condition is met. Sometimes it's impossible to come up with a simple test to see if the loop should end. In cases such as this you should put a safety counter into the loop so the loop is limited in how many times it can recourse. The safety counter has to be a variable that is not reset each time through the loop. It will probably be a module level variable that is passed into the function. When a control value inside the function reaches the max value passed in the recursion tops. Be sure when you write recursive functions not to nest them. Only one level of recursion should be going on at any given point. If you nest recursion you will get lost in the loops. If you see yourself getting in to cyclic recursion, try to redesign the function so you only have one recursive activity going on in the function. The last thing you must keep in mind at all times when writing recursive functions is the stack is only so big. If you write a routine that recourses indefinitely, at some point you will run out of stack. When you run out of stack in AutoLISP, your program quits, which a user fails to see the humor in. Restrict your use of recursion to small loops. DO-WHILE (do It doesn't hold true to the "C" language syntax, but it comes pretty close. If you have used do-while you know how valuable it can be, and it's worth it to have it around. The do-while you see above can be used to do one statement or many if you write do_this as a list. (defun c:less8a ( / do ) (do What the do-while does for you is give you a way to run the statements at least once even if the CHK_FUNC is false. The normal "while" loop only runs if the CHK_FUNC is true. This also allows us to initialize the loop, inside the loop. It's a very clean way to keep everything together. FOR (defun c:less8b ( / for ) Just like the do-while, the FOR loop needs everything you pass it quoted. It won't work otherwise. Just like last time also, you may be able to think of a better way to do what I have done, but just be sure you understand, it can be done. |
|