Я пытаюсь написать функцию, используя только функции Common Lisp, которые будут подсчитывать количество s-выражений в s-выражении. Например:
((x = y)(z = 1)) ;; returns 2
а также
((x - y)) ;; returns 1
Вложенные выражения возможны так:
((if x then (x = y)(z = w))) ;; returns 3
Я написал функцию, которая находит длину и работает, если нет вложенных выражений. Это:
(define (length exp)
(cond
((null? exp) 0)
(#t (+ 1 (length (cdr exp))))))
Теперь я изменил это, пытаясь поддерживать вложенные выражения, следующим образом:
(define (length exp)
(cond
((null? exp) 0)
((list? (car exp)) (+ 1 (length (cdr exp))))
(#t (length (cdr exp)))))
Это работает для выражений без вложений, но всегда на 1 меньше, чем ответ для вложенных выражений. Это связано с тем, что в приведенном выше примере, ((if x then (x = y)(z = w)))
, сначала будет рассматриваться if
, что удовлетворяет третьему условию, возвращая cdr (остальную часть выражения в виде списка) в length
. То же самое происходит до тех пор, пока не будет достигнуто (x=y), после чего возвращается +1
. Это означает, что выражение (if x then .... )
не было учтено.
Каким образом я мог бы объяснить это? Добавление +2
приведет к пересчету не вложенных выражений.
Мне нужно, чтобы это работало в одной функции, так как вложение может происходить где угодно, поэтому:
((x = y) (if y then (z = w)))