Exercise 2.73: 2.3.2 described a
program that performs symbolic differentiation:
(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))))
⟨more rules can be added here⟩
(else (error "unknown expression type:
DERIV" exp))))
We can regard this program as performing a dispatch on the type of the
expression to be differentiated. In this situation the “type tag” of the
datum is the algebraic operator symbol (such as +) and the operation
being performed is deriv. We can transform this program into
data-directed style by rewriting the basic derivative procedure as
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var)
1
0))
(else ((get 'deriv (operator exp))
(operands exp)
var))))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
Explain what was done above. Why can’t we assimilate the predicates
number? and variable? into the data-directed dispatch?
Write the procedures for derivatives of sums and products, and the auxiliary
code required to install them in the table used by the program above.
Choose any additional differentiation rule that you like, such as the one for
exponents (Exercise 2.56), and install it in this data-directed
system.
In this simple algebraic manipulator the type of an expression is the algebraic
operator that binds it together. Suppose, however, we indexed the procedures
in the opposite way, so that the dispatch line in deriv looked like
((get (operator exp) 'deriv)
(operands exp) var)
What corresponding changes to the derivative system are required?
练习 2.73:2.3.2 节描述了一个执行符号微分的程序:
(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))))
⟨more rules can be added here⟩
(else (error “unknown expression type:
DERIV” exp))))
我们可以将这个程序看作对待求导表达式的类型进行分派。在这种情形下,数据的“类型标签”是代数运算符号(如 +),所执行的操作是 deriv。我们可以将此程序改写为数据导向风格——将基本求导过程重写为:
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var)
1
0))
(else ((get 'deriv (operator exp))
(operands exp)
var))))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
解释上述所做的工作。为什么不能将谓词 number? 和 variable? 纳入数据导向的分派中?
编写求和式与积式导数的过程,以及将它们安装到上述程序所用表格中所需的辅助代码。
选择你喜欢的任一附加微分规则,例如指数的规则(练习 2.56),并将其安装到这个数据导向系统中。
在这个简单的代数操纵器中,表达式的类型是将其联结在一起的代数运算符。然而,假设我们以相反的方式为过程建立索引,使得 deriv 中的分派行形如:
((get (operator exp) 'deriv)
(operands exp) var)
对求导系统需要作出哪些相应的改动?
(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))))
⟨more rules can be added here⟩
(else (error "unknown expression type:
DERIV" exp)))) (define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp)
(if (same-variable? exp var)
1
0))
(else ((get 'deriv (operator exp))
(operands exp)
var))))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))