Более простой случай, когда ваш алгоритм не работает: (f '((1 2) 3))
должен привести к '((1 2 3))
, но ваш приведет к ошибке.
Сначала мы определим некоторые термины:
«Элемент» - это обычный элемент, например 1
или 'a
.
«Простой список» - это просто список «элементов» без вложенного списка.
Например, '(1 2 3)
- простой список. '((1 2) 3)
не простой список.
«Простой список» - это либо:
- и
empty
список
- a
cons
"элемента" и следующего "простого списка"
«Список прыжковых пар» - это список четной длины, где нечетный индекс имеет «простой список», а четный индекс имеет элемент. Например, '((1) 2 (a) 4)
- это «список прыжковых пар». «Список прыжковых пар» - это либо:
- и
empty
список
- a
cons
из
- «простой список»
- a
cons
"элемента" и следующего "списка прыжковых пар"
Мы закончили с терминологией. Прежде чем писать функцию, давайте начнем с нескольких примеров:
(f '()) equivalent to (f empty)
should output '()
equivalent to empty
(f '((1 2) 3)) equivalent to (f (cons (cons 1 (cons 2 empty))
(cons 3
empty)))
should output '((1 2 3))
equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
empty)
(f '((1 2) 3 (4) a)) equivalent to (f (cons (cons 1 (cons 2 empty))
(cons 3
(cons (cons 4 empty)
(cons 'a
empty)))))
should output '((1 2 3) (4 a))
equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
(cons (cons 4 (cons 'a empty))
empty))
Итак, f
- это функция, которая использует «список прыжковых пар» и возвращает список «простого списка».
Теперь напишем функцию f
:
(define (f lst)
???)
Обратите внимание, что тип lst
является «списком прыжковых пар», поэтому мы выполним анализ случая непосредственно:
(define (f lst)
(cond
[(empty? lst) ???] ;; the empty list case
[else ??? ;; the cons case has
(first lst) ;; the "plain list",
(first (rest lst)) ;; the "element", and
(rest (rest lst)) ;; the next "list of jumping pairs"
???])) ;; that are available for us to use
Из примера:
(f '()) equivalent to (f empty)
should output '()
equivalent to empty
мы знаем, что пустой регистр должен возвращать пустой список, поэтому давайте заполним соответствующее отверстие:
(define (f lst)
(cond
[(empty? lst) empty] ;; the empty list case
[else ??? ;; the cons case has
(first lst) ;; the "plain list",
(first (rest lst)) ;; the "element", and
(rest (rest lst)) ;; the next "list of jumping pairs"
???])) ;; that are available for us to use
Из примера:
(f '((1 2) 3)) equivalent to (f (cons (cons 1 (cons 2 empty))
(cons 3
empty)))
should output '((1 2 3))
equivalent to (cons (cons 1 (cons 2 (cons 3 empty)))
empty)
мы знаем, что мы определенно хотим поместить «элемент» в конец «простого списка», чтобы получить результирующий «простой список», который нам нужен:
(define (f lst)
(cond
[(empty? lst) empty] ;; the empty list case
[else ;; the cons case has:
???
;; the resulting "plain list" that we want
(append (first lst) (cons (first (rest lst)) empty))
;; the next "list of jumping pairs"
(rest (rest lst))
;; that are available for us to use
???]))
Остался еще один «список прыжковых пар», с которым нам нужно разобраться, но у нас уже есть способ справиться с ним: f
!
(define (f lst)
(cond
[(empty? lst) empty] ;; the empty list case
[else ;; the cons case has:
???
;; the resulting "plain list" that we want
(append (first lst) (cons (first (rest lst)) empty))
;; the list of "plain list"
(f (rest (rest lst)))
;; that are available for us to use
???]))
И тогда мы можем вернуть ответ:
(define (f lst)
(cond
[(empty? lst) empty] ;; the empty list case
[else ;; the cons case returns
;; the resulting list of "plain list" that we want
(cons (append (first lst) (cons (first (rest lst)) empty))
(f (rest (rest lst))))]))