Вот как я должен систематически проектировать такую функцию, используя части рецепта проектирования из Как разрабатывать программы .
Входные данные представляют собой список, который может содержать числа и списки чисел. Сейчас я предполагаю, что списки могут быть вложены дальше, чем это. Если разрешить произвольно вложенные списки, то это сделает дерево чисел, а не просто список.
;; A NumTree is one of:
;; - Number
;; - [Listof NumTree]
;; sum : NumTree -> Number
(define (sum nt)
???)
«Один из» в приведенном выше определении данных означает функцию следует использовать условное выражение с вопросом для каждого маркера в поле «один из».
;; sum : NumTree -> Number
(define (sum nt)
(cond [(number? nt) ???]
[(list? nt) ???]))
В случаях определения данных нет никаких «подчастей», поэтому следующим шагом является поиск ссылок на сложные определения данных, включая собственные ссылки, и вставка вспомогательных функций для них. [Listof NumTree]
является сложным определением данных, поэтому создайте вспомогательную функцию для его суммирования.
Сначала добавьте эту функцию в свой "список wi sh", к ней вы вернетесь позже.
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
???)
Теперь, когда он находится в вашем списке wi sh, используйте его, чтобы завершить sh, определяя остальную часть sum
.
;; sum : NumTree -> Number
(define (sum nt)
(cond [(number? nt) nt]
[(list? nt) (sum-listof-numtree nt)]))
Теперь, когда это сделано, go вернитесь к ваш список sh и работа на sum-listof-numtree
. Опять же, вы можете основать его на определении данных, на этот раз для Listof
.
;; A [Listof NumTree] is one of:
;; - '()
;; - (cons NumTree [Listof NumTree])
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
???)
Снова "один из" превращается в cond
, с ветвью для каждой точки маркера.
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
(cond [(empty? lont) ???]
[(cons? lont) ???]))
Здесь корпус cons
состоит из двух частей: first
и rest
.
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
(cond [(empty? lont) ???]
[(cons? lont) (.... (first lont) (rest lont) ....)]))
Следующим шагом является проверка наличия какой-либо из частей сложные определения данных, и, если они есть, вставка вспомогательных функций. В этом случае оба являются сложными данными. (first lont)
- это NumTree
, а (rest lont)
- это [Listof NumTree]
.
Функция "helper" для NumTree
здесь равна sum
, поэтому в шаблоне вы можете использовать (sum (first lont))
. А «вспомогательная» функция для [Listof NumTree]
равна sum-listof-numtree
, поэтому вы можете использовать для этого (sum-listof-numtree (rest lont))
.
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
(cond [(empty? lont) ???]
[(cons? lont) (.... (sum (first lont)) (sum-listof-numtree (rest lont)) ....)]))
Теперь просто заполните отверстия тем, что имеет смысл для суммирования.
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
(cond [(empty? lont) 0]
[(cons? lont) (+ (sum (first lont)) (sum-listof-numtree (rest lont)))]))
В совокупности они образуют пару взаимно рекурсивных функций, работающих с парой взаимно рекурсивных определений данных.
;; A NumTree is one of:
;; - Number
;; - [Listof NumTree]
;; A [Listof NumTree] is one of:
;; - '()
;; - (cons NumTree [Listof NumTree])
;; sum : NumTree -> Number
(define (sum nt)
(cond [(number? nt) nt]
[(list? nt) (sum-listof-numtree nt)]))
;; sum-listofnumtree : [Listof NumTree] -> Number
(define (sum-listof-numtree lont)
(cond [(empty? lont) 0]
[(cons? lont) (+ (sum (first lont)) (sum-listof-numtree (rest lont)))]))