Copy ; define a symbol
( define alpha 27)
( quote alpha )
'alpha
;; ' is a shorthand for quote
; retrieve the value associated with symbol
alpha
; reference the symbol
( quote alpha )
'alpha
; operations
( symbol? ( quote alpha )) ; test whether an object is a symbol
( eq? 'alpha 'alpha) ; test equality of two symbols
由前面的章节,我们知道 Scheme 在对表达式解析时,会先判断表达式类型。比如 lambda 表达式,那么 Scheme 的 evaluator 会认为这是一种特殊表达式,它的评价方式是创建一段对应的程序,然后返回指向该程序的指针,这时候我们就会看到 #[compound-…] 这样的打印输出结果。
同样的道理,Scheme 如果遇到 quote 表达式,它也会认为这是一种特殊表达式,它的评价方式就是为表达式中的第二个子表达式创建内部表示 (internal representation) 并返回,这时候 Scheme 会把对应的内部表示打印出来 — 即 beta。
Copy ( list ( quote delta ) ( quote delta ))
但 Scheme 的解释器内部实际上会记住过往的 symbols,因此解释器内部不会存在两个一模一样的 symbol,即这个 symbol 是全局唯一的。因此上文中的表达式实际上在解释器内部表示如下图所示:
Copy ( define x 20)
( + x 3 ) ; => 23
' ( + x 3 ) ; => (+ x 3)
( list ( quote + ) x '3) ; => (+ 20 3)
( list '+ x 3 ) ; => (+ 20 3)
( list + x 3 ) ; => ([procedure #...] 20 3)
Copy ; (deriv <expr> <with-respect-to-var>) ==> <new-expr>
;
; syntax
; Expr = SimpleExpr | CompoundExpr
; SimpleExpr = number | symbol
; CompoundExpr = pair< (+|*), pair<Expr, pair<Expr, null> >>
; usage
; (deriv '(+ x 3) 'x) ; => 1
; (deriv '(+ (* x y) 4) 'x) ; => y
; (deriv '(* x x) 'x) ; => (+ x x)
; implementation
( define simple-expr? ( lambda (e)
( not ( pair? e))))
( define deriv ( lambda (expr var)
( if (simple-expr? expr)
( if ( number? expr) 0
( if ( eq? expr var) 1 0 ))
( if ( eq? ( car expr) '+ )
( list '+
(deriv ( cadr expr) var)
(deriv ( caddr expr) var))
<handle product expression>
)
))
)
; 缺点
; 1. 可读性差 <- 没有明确的函数名告诉读者每段程序在做什么
; 2. 对新操作的扩展性差 <- 因为目前的代码假设只有两种操作,利用嵌套 if 语句来完成
; 3. 对表达式的表示形式不可变 <- 如果我们要改变表达式的表示形式,比如 '(x + 3),代码将发生巨大改变,因为我们依赖了 list 结构,以及它的选择器, car, cdr, cadr ... 而没有抽象出 Expr 这种抽象数据类型。
; 改进
; 1. 使用 cond 而不是嵌套if
( define sum-expr? ( lambda (e)
( and ( pair? e) ( eq? ( car e) '+ ))))
( define variable? ( lambda (e)
( and ( not ( pair? e)) ( symbol? e))))
; 2. 使用数据抽象
( define make-sum ( lambda (e1 e2)
( list '+ e1 e2)))
( define addend ( lambda (sum) ( cadr sum)))
( define augend ( lambda (sum) ( caddr sum)))
; deriv
( define deriv ( lambda (expr var)
( cond
(( number? expr) 0 )
((variable? expr) ( if ( eq? expr var) 1 0 ))
((sum-expr? expr)
(make-sum (deriv (addend expr) var)
(deriv (augend expr) var)))
((product-expr? expr)
<handle product expression>)
( else
(error "unknown expression type" expr))
)
))
; 此时 (deriv (make-sum 'x 'y) 'x) => '(+ 1 0),但我们希望得到的是约减过的表达式 '1,为了得到后者
( define make-sum
( lambda (e1 e2)
( cond (( number? e1)
( if ( number? e2)
( + e1 e2)
( list '+ e1 e2)))
(( number? e2)
( list '+ e2 e1))
( else ( list '+ e1 e2)))))