Сказать, какой смысл определять комплексные числа с действительными и мнимыми частями, не являющимися действительными числами, мне трудно. Тем не менее, легко представить, что в системе существует несколько различных представлений действительных чисел (например, различающихся точностью и объемом требуемой памяти). В таком случае задача имеет смысл.
Я не буду приводить весь код модифицированной системы, а просто укажу какие изменения и где потребуется внести.
Во-первых, нам понадобится заменить во внутренних операциях пакета комплексных, а также пакетов декартового и полярного представлений чисел использование стандартных операторов сложения, вычитания, умножения и деления на соответствующие обобщенные процедуры. Соответствующие изменения будут выглядеть так:
;install-complex-package
(define (add-complex z1 z2)
(make-from-real-imag (add (real-part z1) (real-part z2))
(add (imag-part z1) (imag-part z2))))
(define (sub-complex z1 z2)
(make-from-real-imag (sub (real-part z1) (real-part z2))
(sub (imag-part z1) (imag-part z2))))
(define (mul-complex z1 z2)
(make-from-mag-ang (mul (magnitude z1) (magnitude z2))
(add (angle z1) (angle z2))))
(define (div-complex z1 z2)
(make-from-mag-ang (div (magnitude z1) (magnitude z2))
(sub (angle z1) (angle z2))))
;install-rectangular-package
(define (magnitude z)
(sqrt (add (square (real-part z))
(square (imag-part z)))))
(define (make-from-mag-ang r a)
(cons (mul r (cosine a)) (mul r (sine a))))
;install-polar-package
(define (real-part z)
(mul (magnitude z) (cosine (angle z))))
(define (imag-part z)
(mul (magnitude z) (sine (angle z))))
(define (make-from-real-imag x y)
(cons (sqrt (add (square x) (square y)))
(arctan y x)))
Обратите внимание, на то, что имена тригонометрических процедур изменились. Это неспроста!
Во-вторых, нам потребуется реализовать процедуры, использующиеся при переводе из полярного в декартовое представления и обратно, как обобщенные операции для всех типов чисел, которые мы хотим разрешить для использования в компонентах комплексного числа, и добавить эти обобщенные операции в систему (обобщенная процедура плюс набор реализаций для каждого типа).
Операции, которые требуется сделать обобщенными:
На самом деле square и sqrt можно и не делать обобщенными операциями, а просто заменить в их определениях арифметические операции на обобщенные. Например, так:
(define (square x)
(mul x x))
(define (average x y)
(div (add x y) 2.0))
(define (sqrt x)
(fixed-point (average-damp (lambda (y) (div x y)))
1.0))
Однако при этом константы 1.0 и 2.0 (или любые другие типизированные константы) вынудят систему приводить типы.
Описывать реализацию sin, cos и atan как обобщенных операций полностью я не буду. Она абсолютно аналогична ранее введенным обобщенным операциям. Так же добавляются определения обобщенных процедур (они будут называться несколько иначе: sine, cosine и arctan) через apply-generic и конкретные процедуры для каждого типа добавляются с помощью put в таблицу типов в каждом пакете. Для обычных чисел это будет выглядеть так:
;generic functions
(define (sine x) (apply-generic 'sine x))
(define (cosine x) (apply-generic 'cosine x))
(define (arctan x) (apply-generic 'arctan x))
;install-scheme-number-package
(put 'sine '(scheme-number) (lambda (x) (tag (sin x))))
(put 'cosine '(scheme-number) (lambda (x) (tag (cos x))))
(put 'arctan '(scheme-number scheme-number) (lambda (x y) (tag (atan x y))))
Для других типов все аналогично и выписать реализацию несложно.