;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;                                  TEMPLATES                             ;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; --------------------------------- structures --------------------------------
;; -----------------------------------------------------------------------------

(define-struct structureA (fieldA fieldB fieldC))
;; StructureA is (make-structureA X Y Z)

;; fun-of-StructureA: StructureA -> ?
;; strategy: structural design
(define (fun-of-StructureA arg)
  (... (structureA-fieldA arg) 
   ... (structureA-fieldB arg)
   ... (structureA-fieldC arg)))


;; ---------------------------------- unions -----------------------------------
;; -----------------------------------------------------------------------------

;; UnionA is one of
;; -- X
;; -- Y
;; -- Z

;; fun-of-UnionA: UnionA -> ?
;; strategy: structural design (conditional)
(define (fun-of-UnionA arg)
  (cond [(X? arg) ...]
        [(Y? arg) ...]
        [(Z? arg) ...]))


;; ---------------------------------- mixing data ------------------------------
;; -----------------------------------------------------------------------------

(define structureB (fieldA fieldB))
;; StructureB is (make-structureB Z W)

;; UnionB is one of
;; -- StructureA
;; -- StructureB

;; fun-of-UnionB: UnionB -> ?
;; strategy: structural design
(define (fun-of-UnionB arg)
  (cond [(structureA? arg) (... (fun-of-structureA arg) ...)]
        [(structureB? arg) (... (fum-of-structureB arg) ...)]))

;; UnionB is one of
;; -- (make-structureA X Y Z)
;; -- StructureB

;; fun-of-UnionB: UnionB -> ?
;; strategy: structural design
(define (fun-of-UnionB arg)
  (cond [(structureA? arg) (... (structureA-field1 arg) ... 
                            ... (structureA-field2 arg) ...
                            ... (structureA-field3 arg) ...)]
        [(structureB? arg) (... (fun-of-StructureB arg) ...)]))

(define-struct structureC (fieldA fieldB))
;; StructureC is (make-structureC StructureA UnionA)

;; fun-of-StructureC: StructureC -> ?
;; strategy: structural design
(define (fun-of-StructureC arg)
  (... (fun-of-StructureA (structureC-fieldA arg))
   ... (fun-of-UnionA (structureC-fieldB arg)) ....))


;; --------------------------- self-referential data ---------------------------
;; -----------------------------------------------------------------------------

(define-struct structureD (fieldA fieldB))
;; UnionC is one of
;; -- X
;; -- (make-structureD Y UnionC)

;; fun-of-UnionC: UnionC X -> ?
;; strategy: structural design on argA (structural recursion)
(define (fun-of-UnionC argA arbB)
  (cond [(X? argA) ...]
        [else (... (structureD-fieldA argA) 
               ... (structureD-firleB argA)    
               ... (fun-of-UnionC (structureD-fieldB argA )argB) ...)]))

;; fun-of-ListX: [Listof X] Y -> ?
;; strategy: structural design on argA (structural recursion)
(define (fun-of-ListX argA arbB)
  (cond [(emty? argA) ...]
        [else (... (first argA) 
               ... (rest argA) 
               ... (fun-of-ListX (rest argA) argB) ...)]))

;; Note: argB is passed to the recursive call unchanged, otherwise it would
;;       be an accumulator


;; --------------------------- mutually recursive data -------------------------
;; -----------------------------------------------------------------------------

(define-struct structureD (fieldA fieldB))
;;UnionD is one of
;; -- X
;; -- (make-structureD Y UnionE)

;;UnionE is one of
;; -- Z
;; -- (make-structureD W UnionD)

;;fun-of-UnionD: UnionD -> ?
;;strategy: structural design (mutual recursion)
(define (fun-of-unionD arg)
  (cond [(X? arg) ...]
        [else (... (structureD-fieldA arg)
               ... (fun-of-UnionE (structureD-fieldB arg)) ...)]))

;;fun-of-UnionE: UnionE -> ?
;;strategy: structural design (mutual recursion)
(define (fun-of-UnionE arg)
  (cond [(Z? arg) ...]
        [else (... (structureD-fieldA arg)
               ... (fun-of-UnionD (structureD-fieldB arg)) ...)]))


;; ---------------------- processing two pieces of data ------------------------
;; -----------------------------------------------------------------------------

(define structureB (fieldA fieldB))
;; StructureB is (make-structureB Z W)

;;fun-of-StructureB^2: StructureB StructureB -> ?
;; strategy: structural design
(define (fun-of-structureB^2 argA argB)
  (... (structureB-field1 argA) ... (structureB-field2 argA) 
   ... (structureB-field2 argB) ... (structureB-field2 argB)...))
  
;; UnionB is one of
;; -- Z
;; -- W

;;fun-of-unionB^2: UnionB UnionB -> ?
;; strategy: structural design
(define (unionB^2 argA argB)
  (cond [(and (Z? argA) (W? argB)) ...]
        [(and (W? argA) (W? argB)) ...]
        [(and (W? argA) (Z? argB)) ...]
        [(and (Z? argA) (Z? argB)) ...]))


;; ------------------------------ accumulators ---------------------------------
;; -----------------------------------------------------------------------------

(define-struct structureD (fieldA fieldB))
;; UnionC is one of
;; -- X
;; -- (make-structureD Y UnionC)

;; fun-of-UnionC-acc: UnionC Z -> ?
;; strategy: structural design with accumulator (structural recursion)
;; accumulator: the accumulator is the argument argB
;; accumulator invariant: ....
(define (fun-of-UnionC-acc argA argB)
  (cond [(X? arg) ...]
        [else (... (structureD-fieldA argA) 
               ... (fun-of-unionC-acc 
                    (structureD-fieldB argA) 
                    (update-accumulator argB ... ) ...))]))

;; Note: accumulators should not be exposed so a more appropriate context
;;       for the above function is the following:
  
;; fun-of-UnionC: UnionC -> ?
;; strategy: functional composition
(define (fun-of-UnionC argA)
  (local
  ;; fun-of-UnionC-acc: UnionC Symbol -> ?
  ;; strategy: structural design with accumulator (structural recursion)
  ;; accumulator: the accumulator is the argument argB
  ;; accumulator invariant: ....
   [(define (fun-of-UnionC-acc argA argB)
      (cond [(X? arg) ...]
            [else (... (structureD-fieldA argA)
                   ... (fun-of-UnionC-acc
                        (structureD-fieldB argA)
                        (update-accumulator argB ... ) ...))]))])
  (fun-of-UnionC argA initial-value-of-accumulator))
  
  
;; --------------------------- generative recursion ----------------------------
;; -----------------------------------------------------------------------------

;; fun-gen: T -> ?
;; strategy: generative recursion
;; trivial problem: ...
;; trivial solution: ...
;; new problem: ...
;; termination argument: ...
(define (fun-gen problem-instance)
  (cond [(trivial-problem? problem-instance) 
         (trivial-solution problem-instance)]
        [else (combine-problems-solutions 
                 problem-instance 
                 (new-problemA probem-instance)
                 (new-problemB probem-instance)
                 (new-problemC probem-instance))]))
  
;; -----------------------------------------------------------------------------  
  
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;  
;;     MORE TEMPLATES CAN BE CREATED BY EXTENDING THE ABOVE BASIC TEMPLATES    ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;