(define (check-every? check-operator lst)
(cond ((or (null? lst) (= (length lst) 1)) #t)
((check-operator (car lst) (cadr lst)) (check-every? check-operator (cdr lst)))
(else #f)))
Это останавливается, как только начинается первый #f
тест, поэтому он эффективен.
Я хотел сохранить некоторые проверки следующим образом:
;; cave! Erroneous code!!
(define (check-every? check-operator lst)
(cond ((and (null? (cdr lst)) (<= (length lst) 1)) #t)
((check-operator (car lst) (cadr lst)) (check-every? check-operator (cdr lst)))
(else #f)))
Эта стратегия будет работать вобычный lisp, потому что (cdr '())
в общем lisp возвращает '()
.Но в Racket / Scheme это возвращает ошибку.Как запутанно!Спасибо, напомни мне, @coredump!
Я подумал:
(null? (cdr lst))
- это хак для (or (null? lst) (= (length lst) 1))
, однако, если один элемент lst
равен '()
, томы были бы в беде.Но с обычным списком номеров это работает.В противном случае следует использовать более длинный тест.Теперь я исправил (and (null? (cdr lst)) (<= (length lst) 1))
, который - из-за короткого замыкания and
- проверяет только на (null? (cdr lst))
, но, если это правда, дополнительно проверяет, равна ли длина lst
1 или нулю.Только тогда он возвращает #t
для этого случая.Таким образом, эта форма улавливает случай, когда lst
может содержать '()
в качестве элемента где-то еще, чем в последней позиции, по-прежнему сводя к минимуму количество тестов за цикл.
Но хорошо, так как этов Racket невозможно, первая версия самая короткая ...