How to Design Functions

The How to Design Functions recipe consist of:

  1. Signature: The type of each argument separated by a space, followed by ->, followed by the type of the result. ie. Image -> Number

  2. Purpose: A one-line description of the function

  3. Stub: A syntactically complete function definition that produces a value of the right type. The stub serves as a kind of scaffolding to make it possible to run the tests even before the function design is complete.

  4. Examples / Test: These should help you understand what a function is supposed to do. Write at least one test of a call to the function and the expect result. If unsure how to start writing tests use the combination of the function signature and the data definition to help you. Beware of the data definition, even though its example data from its data definition is useful, it doesn’t necessarily cover all the important cases for a particular function.

  5. Template and Inventory: These are produced by following the rules on the Data Driven Templates. Copy the template from the data definition for the consumed type. Rename the template, write a comment explaining where the template was copied from. Remember, for primitive data such as numbers, strings and images the body of the template is simply (... x), where x is the name of the parameter of the function.

  6. Code the function body: fill in the template. Use all of the above to help you code the function body. Rewriting some examples might clarify how to get certain values, which in turn may make it easier to code the function.

  7. Test and debug until correct.

Example using the HtDF recipe in Racket

;; Number -> Number      ; Signature
;; produces n times 2    ; Purpose

(check-expect (double 0) (* 0 2))    ; Tests
(check-expect (double 1) (* 1 2))
(check-expect (double 3) (* 3 2))

;(define (double n) 0)   ; Stub

;(define (double n)      ; Template
;  (... n))

(define (double n)
  (* n 2))