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:

有點難,目前不想寫(其實是不會)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM