Вот как это можно исправить, используя match
и с именем let
, обозначенные ниже как loop
.
(define (split xs)
(let loop ((xs xs) ;; the list, initialized with our input
(l empty) ;; "left" accumulator, initialized with an empty list
(r empty)) ;; "right" accumulator, initialized with an empty list
(match xs
((list a b rest ...) ;; at least two elements
(loop rest
(cons a l)
(cons b r)))
((cons a empty) ;; one element
(loop empty
(cons a l)
r))
(else ;; zero elements
(list (reverse l)
(reverse r))))))
вышемы используем loop
для построения влево и вправо списков, затем мы используем reverse
для возврата окончательного ответа.Мы можем избежать перевернуть ответ, если построим ответ в обратном порядке!Используемая здесь техника называется стиль передачи продолжения .
(define (split xs (then list))
(match xs
((list a b rest ...) ;; at least two elements
(split rest
(λ (l r)
(then (cons a l)
(cons b r)))))
((cons a empty) ;; only one element
(then (list a) empty))
(else ;; zero elements
(then empty empty))))
Обе реализации выполняют в соответствии со спецификацией.
(split '())
;; => '(() ())
(split '(1))
;; => '((1) ())
(split '(1 2 3 4 5 6 7))
;; => '((1 3 5 7) (2 4 6))
Группировка результата в list
являетсяинтуитивно понятный по умолчанию, но, вероятно, вы все равно планируете что-то делать с отдельными частями
(define my-list '(1 2 3 4 5 6 7))
(let* ((result (split my-list)) ;; split the list into parts
(l (car result)) ;; get the "left" part
(r (cadr result))) ;; get the "right" part
(printf "odds: ~a, evens: ~a~n" l r))
;; odds: (1 3 5 7), evens: (2 4 6)
Выше, стиль передачи продолжения дает нам уникальный контроль над возвращаемым результатом.Продолжение настраивается на сайте вызова с использованием второго параметра.
(split '(1 2 3 4 5 6 7) list) ;; same as default
;; '((1 3 5 7) (2 4 6))
(split '(1 2 3 4 5 6 7) cons)
;; '((1 3 5 7) 2 4 6)
(split '(1 2 3 4 5 6 7)
(λ (l r)
(printf "odds: ~a, evens: ~a~n" l r)))
;; odds: (1 3 5 7), evens: (2 4 6)
(split '(1 2 3 4 5 6 7)
(curry printf "odds: ~a, evens: ~a~n"))
;; odds: (1 3 5 7), evens: (2 4 6)
Ответ Оскара с использованием вспомогательной вспомогательной функции или первая реализация в этом посте с использованием loop
- практичные и идиоматические программы.Стиль прохождения продолжения - хорошее академическое упражнение, но я продемонстрировал его здесь только потому, что он показывает, как обойти две сложные задачи:
- создание списка вывода без необходимости его реверсирования
- возврат нескольких значений