大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说日拱一卒,伯克利教你学Lisp,CS61A作业9「建议收藏」,希望您对编程的造诣更进一步.
大家好,日拱一卒,我是梁唐。
我们继续来肝伯克利CS61A,这次我们看的是作业9,同样是基于Lisp语言的几个编程问题。本文始发于公众号:Coder梁
没接触过或者不了解Lisp的同学可以去翻一下我上一篇文章,里面有一些关于Lisp的简单介绍。
这一次的作业一共有五道题,题量和难度都不算大。
好了,废话不多说,我们来看题吧。
Q1: How Many Dots?
实现how-many-dots
方法,它的输入是一个嵌套的scheme list s
,返回的是s
输出时包含的’点’的数量。
你可以假设s
当中只包含数字。
提示:当一个pair中第二个元素不是一个标准的list时会出现’点’。
你可以使用pair?
,null?
,number?
分别来判断一个值是否是一个pair, nil
或数字
解答
这是一个简单的递归运用,对于一个嵌套的pair来说,它的first和second都有可能是一个pair。所以我们需要使用递归来解决。
如果s
是一个pair,那么s
当中点的数量等于s.first
中点的数量和s.second
中点的数量相加。还要加上s.first
和s.second
之间包含的点。什么情况下会在s.first
和s.second
之间出现点呢?答案很简单,当s.second
是数字时。
(define (how-many-dots s)
(cond
((pair? s)
(+ (how-many-dots (car s))
(how-many-dots (cdr s))
(if (number? (cdr s)) 1 0)
)
)
(else 0)
)
)
Differentiation(微分)
接下来需要我们开发一系列函数来实现代数当中的微分,要求能够求一个表达式中某一个变量的微分,变量可以是字母的形式。
derive
过程接收一个代数表达式,和一个变量,返回这个表达式中该变量的微分。
微分是一个递归过程,包含了许多计算规则。
; derive returns the derivative of EXPR with respect to VAR
(define (derive expr var)
(cond ((number? expr) 0)
((variable? expr) (if (same-variable? expr var) 1 0))
((sum? expr) (derive-sum expr var))
((product? expr) (derive-product expr var))
((exp? expr) (derive-exp expr var))
(else 'Error)))
我们使用下列的数据抽象来实现,sums
和products
都是list,分别表示累加和累乘,更多的定义如下:
; Variables are represented as symbols
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
; Numbers are compared with =
(define (=number? expr num)
(and (number? expr) (= expr num)))
; Sums are represented as lists that start with +.
(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 (list? x) (eq? (car x) '+)))
(define (addend s) (cadr s))
(define (augend s) (caddr s))
; Products are represented as lists that start with *.
(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 (list? x) (eq? (car x) '*)))
(define (multiplier p) (cadr p))
(define (multiplicand p) (caddr p))
为了简单起见,我们可以不用考虑使用链式法则嵌套求导的情况。
Q2: Derive Sum
实现derive-sum
过程,对一个求和的过程求导。addend
和augend
表示加法当中相加的两个值。
解答
对于加法求导很简单,就是对相加的表达式进行分别求导,再相加
(define (derive-sum expr var)
(make-sum (derive (addend expr) var) (derive (augend expr) var))
)
Q3: Derive Product
实现derive-product
函数,对乘法表达式进行求导。它接收两个表达式相乘,返回它们的导数。
解答
对乘法求导稍微复杂一些,但是也不算太复杂,高数书里有现成的公式:
我们套用公式即可
(define (derive-product expr var)
(make-sum
(make-product (derive (addend expr) var) (augend expr))
(make-product (addend expr) (derive (augend expr) var))
)
)
Q4: Make Exp
实现make-exp
函数,base
表示底数,exponent
表示指数。base
可以是任何表达式,但可以认为指数一定是非负整数。
对于指数是0或1,或者是底数也是整数的情况,你可以直接返回对应的结果。其他情况,你可以返回如下的表达式:(^ base exponent)
解答
由于exp
表达式是(^ base exponent)
的形式,所以base
就是(cadr exp)
,exponent
就是(caddr exp)
。
make-exp
过程也简单,我们首先判断指数,如果指数为0,那么结果就是1,如果指数为1,结果就是base
。否则则要判断底数是否是数字,如果是数字可以直接求出结果。否则生成对应的表达式。
(define (make-exp base exponent)
(cond ((=number? exponent 0) 1)
((=number? exponent 1) base)
((and (number? base) (number? exponent)) (expt base exponent))
(else (list '^ base exponent))
)
)
(define (base exp)
(cadr exp)
)
(define (exponent exp)
(caddr exp)
)
(define (exp? exp)
(and (list? exp) (eq? (car exp) '^))
)
Q5: Derive Exp
实现derive-exp
函数,利用幂函数的规则进行求导。
解答
我们套用一下幂函数的求导公式:
我们可以使用make-product
函数来求这三项的乘积:(exponent exp)
,(derive (base exp) var)
, (make-exp (base exp) (make-sum (exponent exp) (- 1)))
(define (derive-exp exp var)
(make-product
(make-product (exponent exp) (derive (base exp) var))
(make-exp (base exp) (make-sum (exponent exp) (- 1)))
)
)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/13300.html