2021 fall cs61a project scheme
网址 https://inst.eecs.berkeley.edu/~cs61a/fa21/proj/scheme/#part-i-the-evaluator
problem1:
这一题没什么难度就是注意在lookup函数里面不能用get去找列表里面的值,因为可能值本身就是None
def define(self, symbol, value):
"""Define Scheme SYMBOL to have VALUE."""
# BEGIN PROBLEM 1
self.bindings[symbol] = value
"*** YOUR CODE HERE ***"
# END PROBLEM 1
def lookup(self, symbol):
"""Return the value bound to SYMBOL. Errors if SYMBOL is not found."""
# BEGIN PROBLEM 1
"*** YOUR CODE HERE ***"
# Case 1. we check if the symbol is in the current frame
if symbol in self.bindings.keys():
return self.bindings[symbol]
else:
# Case 2. we check the parent of the current frame repreatly
pos = self.parent
while pos is not None:
if symbol in pos.bindings.keys():
return pos.bindings[symbol]
pos = pos.parent
# ALTERNATIVE: recursion
#if self.parent is not None:
#return self.parent.lookup(symbol)
# Case 3. we can't find the symbol
raise SchemeError('unknown identifier: {0}'.format(symbol))
problem2:
这个题目就是procedure是一个类,然后他有两个属性,一个是函数一个是一个bool值(即是否需要当前帧作为参数传入的一个判断)
然后就是把传进来的args(即参数)全部运用procedure类里面的函数求得值给予返回
def scheme_apply(procedure, args, env):
"""Apply Scheme PROCEDURE to argument values ARGS (a Scheme list) in
Frame ENV, the current environment."""
#env是当前环境(frame?)
validate_procedure(procedure)
if isinstance(procedure, BuiltinProcedure):
# BEGIN PROBLEM 2
"*** YOUR CODE HERE ***"
args_list = []
pos = args
while pos:
if pos.first is not None:
args_list.append(pos.first)
pos = pos.rest
if procedure.expect_env:
args_list.append(env)
try:
return procedure.py_func(*args_list)
except TypeError:
raise SchemeError('incorrect number of arguments')
# END PROBLEM 2
elif isinstance(procedure, LambdaProcedure):
# BEGIN PROBLEM 9
"*** YOUR CODE HERE ***"
# END PROBLEM 9
elif isinstance(procedure, MuProcedure):
# BEGIN PROBLEM 11
"*** YOUR CODE HERE ***"
# END PROBLEM 11
else:
assert False, "Unexpected procedure: {}".format(procedure)
problem3:
这个就是三步,就题干里面的
Evaluate the operator (which should evaluate to an instance of Procedure)
Evaluate all of the operands
Apply the procedure on the evaluated operands by calling scheme_apply, then return the result
def scheme_eval(expr, env, _=None): # Optional third argument is ignored
"""Evaluate Scheme expression EXPR in Frame ENV.
>>> expr = read_line('(+ 2 2)')
>>> expr
Pair('+', Pair(2, Pair(2, nil)))
>>> scheme_eval(expr, create_global_frame())
4
"""
# Evaluate atoms
if scheme_symbolp(expr):
return env.lookup(expr)
elif self_evaluating(expr):
return expr
# All non-atomic expressions are lists (combinations)
if not scheme_listp(expr):
raise SchemeError('malformed list: {0}'.format(repl_str(expr)))
first, rest = expr.first, expr.rest
if scheme_symbolp(first) and first in scheme_forms.SPECIAL_FORMS:
return scheme_forms.SPECIAL_FORMS[first](rest, env)
else:
# BEGIN PROBLEM 3
"*** YOUR CODE HERE ***"
procedure = scheme_eval(first, env)
validate_procedure(procedure)
args = rest.map(lambda x: scheme_eval(x, env))
return scheme_apply(procedure, args, env)
# END PROBLEM 3
problem4:
4和5都是将参数默认前面加上define(或者quote)然后返回
if scheme_symbolp(signature):
# assigning a name to a value e.g. (define x (+ 1 2))
validate_form(expressions, 2, 2) # Checks that expressions is a list of length exactly 2
# BEGIN PROBLEM 4
"*** YOUR CODE HERE ***"
env.define(signature, scheme_eval(expressions.rest.first, env))
return signature
# END PROBLEM 4
problem5:
def do_quote_form(expressions, env):
"""Evaluate a quote form.
>>> env = create_global_frame()
>>> do_quote_form(read_line("((+ x 2))"), env) # evaluating (quote (+ x 2))
Pair('+', Pair('x', Pair(2, nil)))
"""
validate_form(expressions, 1, 1)
# BEGIN PROBLEM 5
"*** YOUR CODE HERE ***"
return expressions.first
# END PROBLEM 5
problem6:
这一题和4和5差不多,就是前面加上begin这个语句,这个语句的作用实在没找到具体的描述,
我的个人理解是按顺序执行begin后面每一个语句,然后返回最后一句的结果
def eval_all(expressions, env):
"""Evaluate each expression in the Scheme list EXPRESSIONS in
Frame ENV (the current environment) and return the value of the last.
>>> eval_all(read_line("(1)"), create_global_frame())
1
>>> eval_all(read_line("(1 2)"), create_global_frame())
2
>>> x = eval_all(read_line("((print 1) 2)"), create_global_frame())
1
>>> x
2
>>> eval_all(read_line("((define x 2) x)"), create_global_frame())
2
"""
# BEGIN PROBLEM 6
if expressions is nil:
return None
if expressions.rest == nil:
return scheme_eval(expressions.first, env) # replace this with lines of your own code
scheme_eval(expressions.first, env)
return eval_all(expressions.rest, env)
# END PROBLEM 6
problem7:
这个也和前面一样相当于在给定的expression前面加一个lambda,再return
def do_lambda_form(expressions, env):
"""Evaluate a lambda form.
>>> env = create_global_frame()
>>> do_lambda_form(read_line("((x) (+ x 2))"), env) # evaluating (lambda (x) (+ x 2))
LambdaProcedure(Pair('x', nil), Pair(Pair('+', Pair('x', Pair(2, nil))), nil), <Global Frame>)
"""
validate_form(expressions, 2)
formals = expressions.first
validate_formals(formals)
# BEGIN PROBLEM 7
"*** YOUR CODE HERE ***"
return LambdaProcedure(formals, expressions.rest, env)
# END PROBLEM 7
problem8:
这里就是创建一个子帧然后传进去一下定义好的变量
def make_child_frame(self, formals, vals):
"""Return a new local frame whose parent is SELF, in which the symbols
in a Scheme list of formal parameters FORMALS are bound to the Scheme
values in the Scheme list VALS. Both FORMALS and VALS are represented as Pairs.
Raise an error if too many or too few
vals are given.
>>> env = create_global_frame()
>>> formals, expressions = read_line('(a b c)'), read_line('(1 2 3)')
>>> env.make_child_frame(formals, expressions)
<{a: 1, b: 2, c: 3} -> <Global Frame>>
"""
if len(formals) != len(vals):
raise SchemeError('Incorrect number of arguments to function call')
# BEGIN PROBLEM 8
"*** YOUR CODE HERE ***"
child = Frame(self)
while formals is not nil:
child.define(formals.first, vals.first)
formals = formals.rest
vals = vals.rest
return child
# END PROBLEM 8
problem9:
此时的procedure是一个LambdaProcedure,他有的参数是formals(即参数)和body(即函数内容)
先创建一个子帧,将值与参数一一对应,然后执行函数内容
elif isinstance(procedure, LambdaProcedure):
# BEGIN PROBLEM 9
"*** YOUR CODE HERE ***"
child = procedure.env.make_child_frame(procedure.formals, args)
return eval_all(procedure.body, child)
# END PROBLEM 9
problem 10:
这道题目就一种简化的define,弄清楚函数名字,函数参数,函数内容一一对应过去,然后注意需要validate_formals检查参数是否合理
elif isinstance(signature, Pair) and scheme_symbolp(signature.first):
# defining a named procedure e.g. (define (f x y) (+ x y))
# BEGIN PROBLEM 10
"*** YOUR CODE HERE ***"
formals = signature.rest # (x y)
validate_formals(formals)
env.define(signature.first, LambdaProcedure(formals, expressions.rest, env))
return signature.first
# END PROBLEM 10
problem 11:
这个mu是把当前这个函数赋予一个动态作用域(可以从内到外的需要变量,而不需要值传递或者说继承,不管这个函数在哪里定义)的能力
elif isinstance(procedure, MuProcedure):
# BEGIN PROBLEM 11
"*** YOUR CODE HERE ***"
child_frame = env.make_child_frame(procedure.formals, args)
return eval_all(procedure.body, child_frame)
# END PROBLEM 11
def do_mu_form(expressions, env):
"""Evaluate a mu form."""
validate_form(expressions, 2)
formals = expressions.first
validate_formals(formals)
# BEGIN PROBLEM 11
"*** YOUR CODE HERE ***"
return MuProcedure(formals, expressions.rest)
# END PROBLEM 11
problem12:
def do_and_form(expressions, env):
"""Evaluate a (short-circuited) and form.
>>> env = create_global_frame()
>>> do_and_form(read_line("(#f (print 1))"), env) # evaluating (and #f (print 1))
False
>>> # evaluating (and (print 1) (print 2) (print 4) 3 #f)
>>> do_and_form(read_line("((print 1) (print 2) (print 3) (print 4) 3 #f)"), env)
1
2
3
4
False
"""
# BEGIN PROBLEM 12
"*** YOUR CODE HERE ***"
if expressions is nil:
return True
front = scheme_eval(expressions.first, env)
if is_scheme_true(front):
if expressions.rest is nil:
return front
else:
return do_and_form(expressions.rest, env)
else:
return False
# END PROBLEM 12
def do_or_form(expressions, env):
"""Evaluate a (short-circuited) or form.
>>> env = create_global_frame()
>>> do_or_form(read_line("(10 (print 1))"), env) # evaluating (or 10 (print 1))
10
>>> do_or_form(read_line("(#f 2 3 #t #f)"), env) # evaluating (or #f 2 3 #t #f)
2
>>> # evaluating (or (begin (print 1) #f) (begin (print 2) #f) 6 (begin (print 3) 7))
>>> do_or_form(read_line("((begin (print 1) #f) (begin (print 2) #f) 6 (begin (print 3) 7))"), env)
1
2
6
"""
# BEGIN PROBLEM 12
"*** YOUR CODE HERE ***"
if expressions is nil:
return False
if is_scheme_true(scheme_eval(expressions.first, env)):
return scheme_eval(expressions.first, env)
else:
return do_or_form(expressions.rest, env)
# END PROBLEM 12
problem13:
def do_cond_form(expressions, env):
"""Evaluate a cond form.
>>> do_cond_form(read_line("((#f (print 2)) (#t 3))"), create_global_frame())
3
"""
while expressions is not nil:
clause = expressions.first
validate_form(clause, 1)
if clause.first == 'else':
test = True
if expressions.rest != nil:
raise SchemeError('else must be last')
else:
test = scheme_eval(clause.first, env)
if is_scheme_true(test):
# BEGIN PROBLEM 13
"*** YOUR CODE HERE ***"
if clause.rest is not nil:
return eval_all(clause.rest, env)
else:
return scheme_eval(clause.first, env) #这样过不了测试需要改成 return test 就能过实在不知道为什么,如果有人知道请告诉我,麻烦了
# END PROBLEM 13
expressions = expressions.rest
problem14:
这个let可以看这个图
可以理解为,这里面新定义变量,如果用到了没有定义的变量就用全局变量
完成这个变量定义后就可以正常运行后面的语句
def make_let_frame(bindings, env):
"""Create a child frame of Frame ENV that contains the definitions given in
BINDINGS. The Scheme list BINDINGS must have the form of a proper bindings
list in a let expression: each item must be a list containing a symbol
and a Scheme expression."""
if not scheme_listp(bindings):
raise SchemeError('bad bindings list in let form')
names = values = nil
# BEGIN PROBLEM 14
"*** YOUR CODE HERE ***"
pos = bindings
while pos is not nil:
front = pos.first
validate_form(front, 2, 2)
names = Pair(front.first, names)
values = Pair(eval_all(front.rest, env), values)
pos = pos.rest
validate_formals(names)
# END PROBLEM 14
return env.make_child_frame(names, values)
probelm 15:
这个没什么难度
(define (enumerate s)
; BEGIN PROBLEM 15
(define (myfunc s num)
(if (null? s )
nil
(cons (list num (car s)) (myfunc (cdr s) (+ num 1)))
))
(myfunc s 0)
)
problem16:
;You don't need to know what "inorder?" is,
;just use this to compare two numbers and then put the first number in front if the result is True
(define (merge inorder? list1 list2)
(cond
((null? list1) list2)
((null? list2) list1)
((inorder? (car list1) (car list2))
(cons (car list1) (merge inorder? (cdr list1) list2)))
(else
(cons (car list2) (merge inorder? list1 (cdr list2)))))
)
probelm EC1:
尾递归和递归的区别,尾递归在于不需要储存原来的栈,就像下面这个例子,他需要一直记住n(n-1)(n-2)再往下去递归,而尾递归不需要保存前面这一长串,直接是返回一个数字。
尾递归定义:
如果一个函数中所有递归形式的调用都出现在函数的末尾,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,这个特性很重要,因为大多数现代的编译器会利用这种特点自动生成优化的代码。
尾递归原理:
当编译器检测到一个函数调用是尾递归的时候,它就覆盖当前的活动记录而不是在栈中去创建一个新的。编译器可以做到这点,因为递归调用是当前活跃期内最后一条待执行的语句,于是当这个调用返回时栈帧中并没有其他事情可做,因此也就没有保存栈帧的必要了。通过覆盖当前的栈帧而不是在其之上重新添加一个,这样所使用的栈空间就大大缩减了,这使得实际的运行效率会变得更高。
这个是递归
int fact(int n) {
if (n < 0)
return 0;
else if(n == 0 || n == 1)
return 1;
else
return n * fact(n - 1);
}
这个是尾递归
int facttail(int n, int res)
{
if (n < 0)
return 0;
else if(n == 0)
return 1;
else if(n == 1)
return res;
else
return facttail(n - 1, n *res);
}
optional_1:
optional_2:
有点难,目前不想写(其实是不会)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人