DeathKing / Learning-SICP

MIT视频公开课《计算机程序的构造和解释》中文化项目及课程学习资料搜集。
https://learningsicp.github.io
10.95k stars 1.54k forks source link

《Lec3b:符号化求导系统:引用》课程答疑 #102

Closed asukaminato0721 closed 2 years ago

asukaminato0721 commented 4 years ago

看起来没这个 issue,我就自己建了一个,如有冒犯可以 close

asukaminato0721 commented 4 years ago

这段代码是照着黑板敲的

#lang sicp
(define (diff expr var)
  (cond ((constant? expr var) 0)
        ((same-var? expr var) 1 )
        ((sum? expr var) (make-sum (diff (a1 expr) var)
                               (diff (a2 expr) var))
                     )
        ((product? expr var) (make-sum (make-product (m1 expr )(diff (m2 expr) var))
                                   (make-product (m2 expr )(diff (m1 expr) var))
                                   )
                         )
        )
  )
(define (constant? exp var)
  (and (atom? exp)
       (not (eq? exp var)))
  )
(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))
;https://stackoverflow.com/questions/16932619/why-am-i-getting-an-unbound-error-for-atom
(define (same-var? expr var)
  (and (atom? expr)
       (eq? expr var)))
(define (sum? exp var)
  (and (atom? exp)
       (eq? (car exp) '+) )
  )
(define (product? exp var)
  (and (not (atom? exp))
       (eq? (car exp) '*) )
  )
(define (make-sum a1 a2)
'('+ a1 a2)
  )
(define (make-product m1 m2)
(list '*  m1 m2)
  )
(define a1 cadr)
(define a2 caddr)
(define m1 cadr)
(define m2 caddr)
(define foo '(+ a x 1))
(diff foo 'x)

没报错,但是 DrRacket 没有输出。

另外 Telegram,QQ 搜了一圈,没有群组。感觉 Racket 有点小众(或者我应该搜索 Lisp?)

asukaminato0721 commented 4 years ago

已搜到 SICP 群组

asukaminato0721 commented 4 years ago

QQ 群的 Noah.ss 给了答复

sum? make-sum make-product 的定义似乎都有问题,另外 diff 处理的表达式应该是只有三个项的列表。

建议 a1 a2 m1 m2 不要直接定义成 c*r 最好用lambda包装一下。

#lang sicp

(define (diff expr var)
  (cond [(constant? expr var) 0]
        [(same-var? expr var) 1]
        [(sum? expr var)
         (make-sum (diff (a1 expr) var)
                   (diff (a2 expr) var))]
        [(product? expr var)
         (make-sum (make-product (m1 expr) (diff (m2 expr) var))
                   (make-product (m2 expr) (diff (m1 expr) var)))]))

(define (constant? exp var)
  (and (atom? exp)
       (not (eq? exp var))))

(define (atom? x)
  (and (not (null? x))
       (not (pair? x))))

;; https://stackoverflow.com/questions/16932619/why-am-i-getting-an-unbound-error-for-atom

(define (same-var? expr var)
  (and (atom? expr)
       (eq? expr var)))

(define (sum? exp var)
  (and (not (atom? exp))
       (eq? (car exp) '+)))

(define (product? exp var)
  (and (not (atom? exp))
       (eq? (car exp) '*)))

(define (make-sum a1 a2)
  (list '+ a1 a2))

(define (make-product m1 m2)
  (list '*  m1 m2))

(define (a1 expr) (cadr  expr))
(define (a2 expr) (caddr expr))
(define (m1 expr) (cadr  expr))
(define (m2 expr) (caddr expr))

(display (diff '(+ a x) 'x))
(newline)

(display (diff 'x 'x))
(newline)

(display (diff 9 'x))
(newline)
DeathKing commented 4 years ago

如果有任何问题,欢迎提问哦!虽然我没有看群里面的解答,还是为没有明白的同学简单解释一下:

  1. 注意使用 ' 符号构造列表时,内部使用字面量即可。下面是你的代码,
(define (make-sum a1 a2)
'('+ a1 a2) )

请仔细对比以下三条条表达式的结果:

> [eq? (car '('+ 1 2 3)) '+]
#f
> [eq? (car '(+ 1 2 3)) '+]             
#t

; 如果想要使用第一条表达式的思路写,那么就要使用准引用(quasi-quote)
> [eq? (car `(,'+ 1 2 3)) '+]
#t
  1. 将多于2元的表达式传递给 diff 时,例如这里的 '(+ a x 1),实际上是 (+ . (a . (x . (1 . '())))),会被归约(reduce)为
   (diff (+ . (a . (x . (1 . '())))) 'x)
=> (+ (diff a 'x) (diff (x . (1 . '())) 'x))

其中,(diff (x . (1 . '())) 'x) 的待求导表达式缺少运算符,实际上是不会被 diffcond 语句选中的,你可以在 cond 子句中添加一个 else 分支,在该分支抛出一个错误试试。