文章目录
buffer可以看成一个栈,第一个元素是栈顶(current),每次弹出第一个元素(pop_first)
do_xx_form函数传进去的表达式的第一个元素都是xx,然后会在进入函数之前被删除掉,也就是最后进入do_xx_form函数的表达式都是已经删除第一个xx元素的表达式。
P1⭐⭐
scheme_read 读取完整表达式,如果是一个值直接返回,否则栈顶一定是’(',将栈顶删除之后,调用read_tail
read_tail 读取表达式的后部分,先调用scheme_read获得栈顶的值(可能是列表也可能是单值),因为调用scheme_read之后,表达式的栈顶就被pop掉了,因此继续调用read_tail读取除了栈顶元素的表达式后部分,然后将栈顶的值和除了栈顶的值用Pair连接起来。
可以如下图模拟一下比较容易理解
P2⭐
每个帧里有一个字典保存变量值,除了全局帧,每个帧都有个父亲帧,如果一个变量在当前帧找不到,就去它父亲找,最后都找不到就显示错误。
因此要找一个变量就看当前帧有没有,如果找不到就循环找父亲直到全局帧即可。
P3 ⭐
将scheme表示的Pair转换成python的list即可,然后将当前帧的环境也添加到list末尾
P4 ⭐⭐
给定Pair(其实就是列表)类型的表达式,当前的环境。要求计算出表达式的值。
铺垫:
给了一些可以用的函数:
Pair里面有一个map函数,向map函数传进一个单参数的函数fn,则可获得一个新的Pair, 新Pair的元素由将Pair中每个元素都通过fn进行变换获得
scheme_apply:传入一个操作和一个表达式,返回对表达式进行该操作后的值
因此直接递归调用,将scheme_eval函数作为fn传入Pair的map函数(因为scheme_eval是双参函数,因此可以用一个lambda表达式先将env传进去,将其转变为单参函数),获得Pair每个元素的取值。 然后调用scheme_apply,将Pair的第一个元素作为操作,其余的元素作为操作。
P5 define变量⭐
定义类似c语言的define语句,且只定义变量,不定义行为,因此是很简单的哟。
define函数传入的是一个表达式和环境,表达式是list,list第一个元素是要定义的变量名,第二个元素是要变量名要绑定的值。因此只需要调用一下
s
c
h
e
m
e
_
e
v
a
l
scheme\_eval
scheme_eval计算一下第二个元素的值,再在环境中将变量名和值绑定即可。
P6 quote & ’ ⭐⭐
q u o t e quote quote就是用来保留它后面的表达式,即不对其进行任何运算直接输出。比如(quote 6),最后获得6。(quote 6 + 7),仍然获得6 + 7。因此在 d o _ q u o t e _ f o r m do\_quote\_form do_quote_form函数中直接返回表达式的第一个元素即可(因为表达式第一个元素 ′ q u o t e ′ 'quote' ′quote′已经被处理掉了。而如果是 ′ ' ′,则需要在 s c h e m e r e a d scheme_read schemeread函数中预先处理,将 ′ ' ′变成 ′ q u o t e ′ 'quote' ′quote′,还需要将’后面的表达式再套进一个pair里,以便和 d o q u o t e f o r m do_quote_form doquoteform统一,因为在 d o q u o t e f o r m do_quote_form doquoteform中会仅提取第一个元素。
P7 eval_all(连续赋值)⭐
eval_all 传入很多个表达式,将所有表达式都赋值之后,eval_all返回最后一个表达式的值。除了第一个,前面的表达式可能会对环境变量产生影响,因此可能对最后一个表达式产生影响,因此需要按顺序赋值哟。
P8 λ \lambda λ⭐
用Pair形式表示一个lambda表达式。但是它已经给了一个类LambdaProcedure来构造了。所以只需要把expressions拆开成【 λ \lambda λ参数formals】和【 λ \lambda λ表达式body】两个部分作为构造类LambdaProcedure的两个参数即可。
P9 define函数 ⭐
在P8的基础上给 λ \lambda λ表达式一个函数名。只需要把给定的expressions拆成【函数名fname】,【 λ \lambda λ参数formals】和【 λ \lambda λbody】三个部分,后面的两部分利用P8形成一个 λ \lambda λ表达式,再在env中将 f n a m e fname fname绑定形成的表达式。
P10 继承帧⭐
原来环境再增加一些变量的绑定。
P11 高阶函数的一小部分⭐
在一个函数a里定义另一个函数b,在函数a调用函数b。
在【调用】函数a会传入参数,因此需要将这些参数绑定到环境中,这题就是用P10进行环境绑定。
P12 ~14 水题
12 and or表达式
13 if-else表达式
14 局部赋值