Complex design problems must be broken into smaller, individual pieces. This can be achieved through the HtDD, HtDF and HtDW recipes. However, often we might need to further break down types and functions into even smaller helper functions.
Suppose, for example, that we have a problem were we are given an arbitrary number of images and we are tasked with designing a function that takes the images and lays them out left-to-right in an increasing order of size.
In this example, we have a function composition problem, where we need a function that must perform two or more distinct and complete operations on consumed data. When we do this, we can remove any data driven template and instead include a main function that calls sub functions in order.
Note that when creating unit tests for function composition, we needn’t create individual tests for each helper function; however, the tests must exercise the combination of the functions. Additionally, for function compositions we do not need to test the base case; however, a test must be included that ensures the scenario works.
When we are in the middle of a function where we switch knowledge domain, we should add another helper function.
Example
;; Data definitions:
;; ListOfImages is one of:
;; - empty
;; - (cons Image ListOfImages)
;; interp. a list of images
(define LOI1 empty)
(define LOI2 (cons (square 10 "solid" "white") empty))
(define LOI3 (cons (square 10 "solid" "white")
(cons (triangle 4 "solid" "white")
(cons (circle 10 "solid" "white")
empty))))
(define LOI4 (cons (rectangle 10 20 "solid" "blue")
(cons (rectangle 20 30 "solid" "red")
empty)))
(define (fn-for-loi loi)
(cond [(empty? loi) (...)]
[else
(... (first loi)
(fn-for-loi (rest loi)))]))
;; Template rules used:
;; - one of: 2 cases
;; - atomic distinct: empty
;; - self-reference: (rest loi) is ListOfImage
;; - compound: (cons Image ListOfNumber)
;; Functions:
;; ListOfImage -> Image
;; sort images in increasing order of size and then lay them out left to right
(check-expect (arrange-images (cons (rectangle 10 20 "solid" "blue")
(cons (rectangle 20 30 "solid" "red")
empty)))
(beside (rectangle 10 20 "solid" "blue")
(rectangle 20 30 "solid" "red")
empty-image))
(check-expect (arrange-images (cons (rectangle 20 30 "solid" "blue")
(cons (rectangle 10 20 "solid" "red")
empty)))
(beside (rectangle 10 20 "solid" "blue")
(rectangle 20 30 "solid" "red")
empty-image))
#;
(define (arrange-images loi) empty-image)
#;
(define (arrange-images loi)
(cond [(empty? loi) (...)]
[else
(... (first loi)
(arrange-images (rest loi)))]))
; Function composition case
(define (arrange-images loi)
(layout-images (sort-images loi)))
;; ListOfImages -> Image
;; place images beside each other in order of list
;; !!!
(define (layout-images loi) empty-image)
;; ListOfImage -> ListOfImage
;; sort images in increase order of size
(check-expect (sort-images empty) empty-image)
(check-expect (sort-images (cons (rectangle 10 20 "solid" "blue")
(cons (rectangle 20 30 "solid" "red")
empty))))
(define (sort-images loi) loi)