length
- это, как правило, антишаблон в схеме, поскольку для получения результата необходимо прочитать весь список.У. Несс отмечает, что map
не меняет структуру списка, а поведение filter
основано на значениях списка , ни то, ни другое не соответствует вашим потребностям.
Вместо того, чтобы сначала делать потенциально дорогостоящие вычисления или неловко применять библиотечные функции, вы можете вычислить init
списка с использованием прямой рекурсии -
(define (init l)
(cond ((null? l)
(error 'init "cannot get init of empty list"))
((null? (cdr l))
null)
(else
(cons (car l)
(init (cdr l))))))
(init '(a b c d e)) ;; '(a b c d)
(init '(a)) ;; '(a)
(init '()) ;; init: cannot get init of empty list
Или хвосто-рекурсивной формы, котораяиспользуется только один reverse
-
(define (init l)
(let loop ((acc null)
(l l))
(cond ((null? l)
(error 'init "cannot get init of empty list"))
((null? (cdr l))
(reverse acc))
(else
(loop (cons (car l) acc)
(cdr l))))))
(init '(a b c d e)) ;; '(a b c d)
(init '(a)) ;; '(a)
(init '()) ;; init: cannot get init of empty list
И, наконец, хвостово-рекурсивная форма, которая не использует length
или reverse
.Для получения дополнительной информации о том, как это работает, см. «Как работают функции коллектора в схеме?» -
(define (init l (return identity))
(cond ((null? l)
(error 'init "cannot get init of empty list"))
((null? (cdr l))
(return null))
(else
(init (cdr l)
(lambda (r)
(return (cons (car l) r)))))))
(init '(a b c d e)) ;; '(a b c d)
(init '(a)) ;; '(a)
(init '()) ;; init: cannot get init of empty list