练习 2.58

a)

将加法的计算函数改成中序表示:

;;; 58-sum.scm

(define (make-sum a1 a2)
    (cond ((=number? a1 0)
            a2)
          ((=number? a2 0)
            a1)
          ((and (number? a1) (number? a2))
            (+ a1 a2))
          (else
            (list a1 '+ a2))))              ; 修改

(define (sum? x)
    (and (pair? x)
         (eq? (cadr x) '+)))                ; 修改

(define (addend s)
    (car s))                                ; 修改

(define (augend s)
    (caddr s))

将加法的计算函数改成中序表示:

;;; 58-product.scm

(define (make-product m1 m2)
    (cond ((or (=number? m1 0) (=number? m2 0))
            0)
          ((=number? m1 1)
            m2)
          ((=number? m2 1)
            m1)
          ((and (number? m1) (number? m2))
            (* m1 m2))
          (else
            (list m1 '* m2))))              ; 修改

(define (product? x)
    (and (pair? x)
         (eq? (cadr x) '*)))                ; 修改

(define (multiplier p)
    (car p))                                ; 修改

(define (multiplicand p)
    (caddr p))

deriv 的代码和书本 100 页给出的一样,不必修改:

;;; 58-deriv.scm

(load "58-sum.scm")
(load "58-product.scm")

(define (deriv exp var)
    (cond ((number? exp)
            0)
          ((variable? exp)
            (if (same-variable? exp var)
                1
                0))
          ((sum? exp)
            (make-sum (deriv (addend exp) var)
                      (deriv (augend exp) var)))
          ((product? exp)
            (make-sum
                (make-product (multiplier exp)
                              (deriv (multiplicand exp) var))
                (make-product (deriv (multiplier exp) var)
                              (multiplicand exp))))
          (else
            (error "unknown expression type -- DERIV" exp))))

;; number

(define (=number? exp num)
    (and (number? exp)
         (= exp num)))

;; variable

(define (variable? x)
    (symbol? x))

(define (same-variable? v1 v2)
    (and (variable? v1)
         (variable? v2)
         (eq? v1 v2)))

测试:

1 ]=> (load "58-deriv.scm")

;Loading "58-deriv.scm"...
;  Loading "58-sum.scm"... done
;  Loading "58-product.scm"... done
;... done
;Value: same-variable?

1 ]=> (make-product 'x 'y)

;Value 11: (x * y)

1 ]=> (make-sum 'x 'y)

;Value 12: (x + y)

1 ]=> (deriv '((x * y) * (x + 3)) 'x)

;Value 13: ((x * y) + (y * (x + 3)))

b)

如果允许使用标准代数写法的话,那么我们就没办法只是通过修改谓词、选择函数和构造函数来达到正确计算求导的目的,因为这必须要修改 deriv 函数,提供符号的优先级处理功能。

比如说,对于输入 x + y * z ,有两种可能的求导顺序会产生(称之为二义性文法),一种是 (x + y) * z ,另一种是 x + (y * z) ;对于求导计算来说,后一种顺序才是正确的,但是这种顺序必须通过修改 deriv 来提供,只是修改谓词、选择函数和构造函数是没办法达到调整求导顺序的目的的。

See also

查看维基词条 Ambiguous grammer 了解更多关于二义性文法的信息。

讨论

blog comments powered by Disqus