...
- Avoid code duplication. I.e., increase code reuse.
- Avoid recomputation.
This sometimes provides dramatic benefits. Avoid re-mentioning an unchanging argument. - To hide the name of helper functions. An AsideWhile important conceptually, most aside: many programming languages (including SchemeJava) provide alternate mechanisms for this (such as
public
/private
attributes) for hiding helper functions and data which scale better to large programs . These mechanisms typically have names like modules orpackages. As this one example shows, even small programs can get a bit less clear when hiding lots of helpersand accomodate the unit testing of hidden functions (whichlocal
does not!). - Name individual parts of a computation, for clarity.On the other hand, don't get carried away.
Here are two easy ways to misuse local:
Code Block |
---|
;; max-num: non-empty-list-of-number -> number (define (max-num a-nelonalon) (local [(define max-rest (max-num (rest a-nelonalon)))] (cond [(empty? (rest a-nelonalon)) (first a-nelonalon)] [else (if (<= (first a-nelonalon) max-rest) max-rest (first a-nelonalon))]))) |
Try running this example on any legal input (according to the contract). It blows up!Question: What's wrong with this?
Make sure you don't put a local too early in your code.
Code Block |
---|
;; max-num: non-empty-list-of-number -> number (define (max-num a-nelonalon) (cond [(empty? (rest a-nelonalon)) (first a-nelonalon)] [else (local [(define max-rest (max-num (rest a-nelonalon))) (define first-smaller? (<=(first a-nelonalon) max-rest))] (if first-smaller? max-rest (first a-nelonalon)))])) |
This isn't wrong, but the local definition of first-smaller?
is unnecessary. Since the comparison is only used once, this refactoring is not a case of code reuse or recomputation. It provides a name to a part of the computation, but whether that improves clarity in this case is a judgement call.
...