Cleaning up code through helper functions

We came up with the following code, that correctly computes the cost for an order
of pens, either with or without a slogan printed on them:

;; single-pen-cost:  Number -> Number
;; consumes the number of pens in an order and produces the cost of a single pen
;; (where 10 or fewer cost 75 cents each, otherwise cost 50 cents each
(define (single-pen-cost num-pens)
  (if (<= num-pens 10)
       0.75
       0.50))
       
;; printed-pen-cost : Number String -> Number
;; consumes number of pens to order and a slogan and produces total order cost
;; where slogans cost 2 cents per letter per pen, and a $3
;; surcharge is added to the cost of the order for printed pens
(define (printed-pen-cost num-pens slogan)
  (if (> (string-length slogan) 0)
	 (+ (* (+ (* 0.02 (string-length slogan)) (single-pen-cost num-pens)) num-pens) 3)
      (* (+ (* 0.02 (string-length slogan)) (single-pen-cost num-pens)) num-pens)))

This code is rather ugly.  Not to mention, it has the same somewhat
complicated computation twice, which gives us twice as much work to do
if we decide to change the formula for pen pricing.  What should we do
about this?

Whenever you see the same computation multiple times in a program, you 
should create a separate function for that computation and call that
function instead.  This 

  - makes the program easier to read (because the function has a
    descriptive name)

  - lets you edit the program in only one place if something changes

To make the helper function, pull out the common code:

(* (+ (* 0.02 (string-length slogan)) (single-pen-cost num-pens)) num-pens)  

Then wrap a function header (name and inputs) around the common code.
As inputs, you need whatever names are used in the common code that
aren't built-in or defined as constants.

  (define (cost-without-surcharge num-pens slogan)
    (* (+ (* 0.02 (string-length slogan)) (single-pen-cost num-pens)) num-pens))

Don't forget to add the signature and purpose:

  ;; cost-without-surcharge : Number String -> Number
  ;; consumes number of pens and slogan and produces cost for pens with slogan, without the surcharge
  (define (cost-without-surcharge num-pens slogan)
     (* (+ (* 0.02 (string-length slogan)) (single-pen-cost num-pens)) num-pens)
  
Now, replace the common expression in the original code with a call to
your new helper function.

  ;; printed-pen-cost : Number String -> Number
  ;; consumes number of pens to order and a slogan and produces total order cost
  (define (printed-pen-cost num-pens slogan)
    (if (> (string-length slogan) 0) 
        (+ (cost-without-surcharge num-pens slogan) 3)
	  (cost-without-surcharge num-pens slogan)))

This code can be cleaned up even further.  Let's look at cost-without-surcharge
again.  Even though there are no repeated computations in this code, it still looks
rather complicated.  Let's define a helper simply to reduce the level of
complexity of the code.  For example, we could write a helper function that
calculates the cost of a slogan:

;; cost-of-slogan:  String -> Number
;; consumes a slogan to be printed on each pen, and produces 
;; the cost of printing the slogan (2 cents per letter)
(define (cost-of-slogan slogan)
  (* 0.02 (string-length slogan)))

cost-without-surcharge then becomes:

;; cost-without-surcharge:  Number String -> Number
;; consumes number of pens and slogan and produces cost for pens with slogan, without the surcharge
(define (cost-without-surcharge num-pens slogan)
   (*  (+ (cost-of-slogan slogan) (single-pen-cost num-pens))
       num-pens))


Finally, let's define constants for the price per character (again, to
make it easier to find if we need to change it later) and for the surcharge.  Here's our final
set of functions:

(define CHAR-COST .02)
(define SURCHARGE 3.00)

;; printed-pen-cost : Number String -> Number
;; consumes number of pens to order and a slogan and produces total order cost
(define (printed-pen-cost num-pens slogan)
    (if (> (string-length slogan) 0) 
        (+ (cost-without-surcharge num-pens slogan) SURCHARGE)
	  (cost-without-surcharge num-pens slogan)))


;; cost-without-surcharge:  Number String -> Number
;; consumes number of pens and slogan and produces cost for pens with slogan, without the surcharge
(define (cost-without-surcharge num-pens slogan)
   (*  (+ (cost-of-slogan slogan) (single-pen-cost num-pens))
       num-pens))


;; cost-of-slogan:  String -> Number
;; consumes a slogan to be printed on each pen, and produces 
;; the cost of printing the slogan (2 cents per letter)
(define (cost-of-slogan slogan)
  (* CHAR-COST (string-length slogan)))


;; single-pen-cost:  Number -> Number
;; consumes the number of pens in an order and produces the cost of a single pen
(define (single-pen-cost num-pens)
  (if (<= num-pens 10)
       0.75
       0.50))
       

This is the level of cleanliness and readability we expect in your code.