Вы можете посмотреть на poly-mult
как на рекурсив poly-add
.Учитывая простоту реализации poly-add
.
(define (poly-add p1 p2)
(cond ((empty? p1)
p2)
((empty? p2)
p1)
(else
(cons (+ (car p1)
(car p2))
(poly-add (cdr p1)
(cdr p2))))))
Вы можете реализовать poly-mult
таким образом, используя вспомогательную процедуру, raise
.
(define (poly-mul p1 p2 (e 0))
(if (empty? p1)
empty
(poly-add (raise e (map (curry * (car p1)) p2))
(poly-mul (cdr p1)
p2
(+ e 1)))))
(define (raise e p)
(if (= e 0)
p
(cons 0
(raise (- e 1)
p))))
(poly-mul '(3 4 5) '(5 9 6 2))
;; '(15 47 79 75 38 10)
Определив raise
в качестве внешней процедуры легко увидеть, как мы поднимаем многочлены до следующей степени.Тем не менее, мы могли бы сохранить это поведение внутри poly-mult
, используя цикл и превращая экспоненту (e
) в саму функцию.
(define (poly-mul p1 p2)
(let loop ((p p1) ;; polynomial
(e identity)) ;; exponent
(if (empty? p)
empty
(poly-add (e (map (curry * (car p)) p2))
(loop (cdr p)
(compose (curry cons 0) e))))))
(poly-mul '(3 4 5) '(5 9 6 2))
;; '(15 47 79 75 38 10)
Наконец, использование цикла в poly-mult
облегчаетдля нас, чтобы преобразовать рекурсивный вызов в правильный хвостовой вызов.Операция poly-add
теперь выполняется первой, а обновленный аккумулятор (acc
) передается следующей итерации цикла.
(define (poly-mul p1 p2)
(let loop ((acc empty) ;; accumulator
(p p1) ;; polynomial
(e identity)) ;; exponent
(if (empty? p)
acc
(loop (poly-add acc
(e (map (curry * (car p)) p2)))
(cdr p)
(compose (curry cons 0) e)))))