Вот как я бы систематически выполнял функцию для определения длины списка.
Конечный результат будет
;; length : [Listof Element] -> Number
;; Produces the number of elements in the list
(define (length lst)
(cond
[(empty? lst) 0]
[(cons? lst) (+ 1 (length (rest lst)))]))
Но более важным является систематический процесс, которыйВы можете использовать, чтобы написать еще много программ.Я использую описанный здесь процесс Рецепт проектирования , описанный в книге Как разрабатывать программы .
1: Что такое список?
AСписок либо пуст, либо это комбинация первого элемента с остальными элементами.Этот «остаток» представляет собой другой список.
В Racket «пустой» записывается как '()
, а «объединение» для списков записывается как cons
.
A [Listof Element] is one of:
- '()
- (cons Element [Listof Element])
Некоторыепримеры списков:
'() ; empty
(cons "I'm alone" '()) ; one element "I'm alone"
(cons "Hello" (cons "there" '())) ; two elements "Hello" and "there"
(cons 1 (cons 3 (cons 5 (cons 7 (cons 9 '()))))) ; five elements, odd numbers
2: Что делает length
?
Функция length
берет список и создает число, представляющее число элементов в списке.Пустой список имеет длину 0
, а приведенные выше примеры должны иметь длины 0
, 1
, 2
и 5
.
;; length : [Listof Element] -> Number
;; Produces the number of elements in the list
;; (length '()) = 0
;; (length (cons "I'm alone" '())) = 1
;; (length (cons "Hello" (cons "there" '()))) = 2
;; (cons 1 (cons 3 (cons 5 (cons 7 (cons 9 '()))))) = 5
(define (length lst)
???)
3. Каковы случаи вопределение?
Список либо пуст, либо минусы.Чтобы проверить, является ли он пустым, мы можем использовать cond
с вопросом (empty? lst)
для пустого регистра и вопросом (cons? lst)
для аргумента "против".
(define (length lst)
(cond
[(empty? lst) ???]
[(cons? lst) ???]))
4: Что?части "данных доступны в каждом случае?
В пустом списке нет подразделов.
Однако (cons Element [Listof Element])
состоит из двух подразделов:
- первое,
Element
, - и остальная часть списка,
[Listof Element]
.
Чтобы получить их в рэкет, вы можете использовать first
иrest
соответственно.
(define (length lst)
(cond
[(empty? lst) ???]
[(cons? lst) ... (first lst) ... (rest lst) ...]))
5: Являются ли какие-либо из этих частей сложными данными?
(first lst)
- это просто Element
.Для целей length
это не сложно, и нам не нужно обрабатывать его дальше.
(rest lst)
- это еще один [Listof Element]
, и это сложно.Как мы справимся с этим?Используя вспомогательную функцию.
В этом случае нам нужна вспомогательная функция, которая связана с длиной и принимает в качестве аргумента [Listof Element]
.В этом случае вспомогательной функцией является length
, функция, которую мы в настоящее время определяем !Мы можем использовать его рекурсивно на (rest lst)
, потому что это меньшая часть.
(define (length lst)
(cond
[(empty? lst) ???]
[(cons? lst) ... (first lst) ... (length (rest lst)) ...]))
6: Заполните отверстия, используя как вашу интуицию о том, как должна работать длина, так и примеры, которые мы написали ранее
Первый пример (length '()) = 0
говорит нам, что первое ???
отверстие должно быть заполнено 0
.
(define (length lst)
(cond
[(empty? lst) 0]
[(cons? lst) ... (first lst) ... (length (rest lst)) ...]))
Вторым отверстием, ...
s вокруг первого идлина остальных, сложнее.Но ваша интуиция о длине должна сказать вам, что длина «объединенного» списка первых и остальных должна быть одна плюс длина остальных.Перефразируя это в код:
(define (length lst)
(cond
[(empty? lst) 0]
[(cons? lst) (+ 1 (length (rest lst)))]))
Системные шаги, которые я использовал, объясняются в книге Как разрабатывать программы .