This is a record of the class discussion in answer to the question: What works for helping make programming go faster, and what doesn't? WHAT DOESN'T WORK - What doesn't work (why it might be that it doesn't work) [what you might try that could help in that case] - Using lots of caddr, caar calls (places too much burden on your attention) [helping procedures] - Brute force: trying all combinations of code (recursion is a "fixed point" and not likely to be found by chance) [think of the steps in creating recursion, work from concrete examples] - Staring at the error (not extracting information from the message?) [try looking at $PUB/docs/scm-error-messages.txt, and might try tracing the code, see $PUB/docs/debugging-scm.txt] - Writing the code, then trying the course tests right away, without testing the helping procedures, or running simple tests (when the tests don't work as expected, you have too many places to look for errors) [run your own simple tests, do bottom-up testing of helping procedures first] - Miscommunication with helping procedures (the problem will seem to be located in the helping procedure, but it's actually in the call to it) [write down the type for each helping procedure, write down a comment describing what the helping procedure is to do, write down examples for the helping procedures, which will also help in bottom up testing] - Typing problems with the interpreter (when you type a backspace, the interpreter doesn't recognize that, and gives you an error that, when printed, looks fine) [if you want to use backspace, put the following in your ~/.login file: stty erase '^H' See $PUB/docs/erase-message.txt for more details on this] - Recursing through helping procedures when not called for by the grammar (the program becomes hard to follow and test) [Make the recursion pattern match the recursion pattern in the grammar, as a general rule, have only one recursion per procedure] WHAT WORKS + What works (why it might be that it works) [caution] + Using helping procedues for readability (allows "separation of concerns", which means: it decreases the burden on your attention in the main procedure, where you don't worry about details allows you to focus more on the helping procedure when writing it ) [too many helping procedures may make your code verbose, hard to follow, and take more time to write] + Writing out the code first on paper (helps you resist the "test and debug" time-waster?) [eventually you need to get it on the computer] + For designing recursions: + work from small concrete examples, constructed to show the problem and its cdr as in (foo '(a b c)) and (foo '(b c)) (concrete examples allow you to see the answer from the recursion, without trying to see how it might be constructed; you can also use the questions: what's the answer for the base case? how do I get this answer from the car of the problem and the answer for the recursive call?) [you have to generalize this when working with problems from other kinds of grammars] + thinking about the base case, one step, and the "rest of the journey" (this matches the problem and solution breakdown for flat recursion over lists and also for standard recursion on the natural numbers.) [this only works for certain kinds of recursions, you have to generalize this when working with problems from other kinds of grammars] + Structuring code to match the grammar that describes its input (there really isn't any other easy way to write code that processes grammatical sentences?) [although this always works, sometimes simplifications are possible] + Bottom-up testing: testing helpers separately, before the main procedure (helps isolate problems more quickly, forces you to think of what the helper is really supposed to do) [overelaborate testing can take extra time] + When you have a problem, check (or print out) the inputs given to the helping procedures (this is a strategy for focusing on a likely source of errors) [other things can go wrong too] + Use define in testing to name test cases, etc. (this helps automate your testing, saving typing time) [overelaborate testing can take extra time] + Using indentation (especially in emacs) and matching parentheses (emacs indentation can help you see syntax errors, because when something doesn't format right, it is often syntactically wrong; parenthesis matching catches common errors, use vi -l if using vi, emacs does this automatically) [you can still have semantic errors even if the syntax is right]