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:

有点难,目前不想写(其实是不会)

posted @ 2022-04-24 14:12  天然气之子  阅读(2009)  评论(2编辑  收藏  举报