Проблема в том, что процедура застревает во втором if
, никогда не достигая базового случая из-за того, как структурированы ваши условия. Мы должны разбить задачу на две части: одну процедуру для проверки случаев, когда n <= 0
, и другую для выполнения цикла в общем случае.
Помните, что в процедуре Scheme только результат последнего выражения получает возвращенного - другие выражения выполняются точно, но их результаты игнорируются. В случае выражения if
структурируйте его так, чтобы оно всегда имело часть «else». Сказав это, это должно работать:
(define (aux n)
(if (= n 1)
1
(+ (+ (+ n n) -1)
(aux (+ n -1)))))
(define (square1 n)
(if (= n 0)
0
(if (> n 0)
(aux n)
(aux (- n)))))
Приведенное выше решение является правильным, но не , что идиоматическое. Мы можем сделать лучше!
- Процедура
aux
должна быть внутренней по отношению к основной процедуре, потому что она больше нигде не будет использоваться
- Вместо вложенности
if
с лучше использовать cond
- Мы могли бы использовать существующие процедуры для общей задачи, такие как
zero?
, positive?
, sub1
- Для эффективности мы должны использовать хвостовую рекурсию , когда это возможно
Вот как может выглядеть более идиоматический ответ, он работает так же, как и первый:
(define (square1 n)
(define (aux n acc)
(if (= n 1)
acc
(aux (sub1 n) (+ acc (sub1 (+ n n))))))
(cond ((zero? n) 0)
((positive? n) (aux n 1))
(else (aux (- n) 1))))
В любом случае, все работает как положено:
(square1 -4)
=> 16
(square1 -3)
=> 9
(square1 -2)
=> 4
(square1 -1)
=> 1
(square1 0)
=> 0
(square1 1)
=> 1
(square1 2)
=> 4
(square1 3)
=> 9
(square1 4)
=> 16