У меня есть версия, которая использует только операции «из первых принципов» и является эффективной (не требует более одного прохода через любой из списков, в отличие от решений на основе append
).: -)
Это делается путем определения двух простых строительных блоков (fold
и reverse
), а затем определения flatten
(и его помощника, reverse-flatten-into
) поверх этих (и обратите внимание, как каждыйфункция длиной всего одну или две строки):
;; Similar to SRFI 1's fold
(define (fold1 kons knil lst)
(if (null? lst)
knil
(fold1 kons (kons (car lst) knil) (cdr lst))))
;; Same as R5RS's reverse
(define (reverse lst)
(fold1 cons '() lst))
;; Helper function
(define (reverse-flatten-into x lst)
(if (pair? x)
(fold1 reverse-flatten-into lst x)
(cons x lst)))
(define (flatten . lst)
(reverse (reverse-flatten-into lst '())))
Используются только внешние функции: cons
, car
, cdr
, null?
и pair?
.
Ключевое понимание этой функции заключается в том, что fold
является очень мощной операцией и должна быть частью любого набора инструментов Schemer.И, как видно из кода выше, это так просто построить из первых принципов!