diff --git a/_internal/targets.json b/_internal/targets.json index b61d7d8974..3cd0545cbb 100644 --- a/_internal/targets.json +++ b/_internal/targets.json @@ -1 +1 @@ -[{"due": "9/25/24", "link": "hw/hw03/", "name": "HW 03: Higher-Order Functions", "piazza_name": "HW 03", "release": "9/18/24"}, {"due": "9/27/24", "link": "lab/lab04/", "name": "Lab 04: Recursion", "piazza_name": "Lab 04", "release": "9/23/24"}] +[{"due": "9/25/24", "link": "hw/hw03/", "name": "HW 03: Higher-Order Functions", "piazza_name": "HW 03", "release": "9/18/24"}, {"due": "9/27/24", "link": "lab/lab04/", "name": "Lab 04: Recursion", "piazza_name": "Lab 04", "release": "9/23/24"}, {"due": "10/2/24", "link": "hw/hw04/", "name": "HW 04: Recursion", "piazza_name": "HW 04", "release": "9/25/24"}] diff --git a/assets/slides/08-Recursion_1pp.pdf b/assets/slides/08-Recursion_1pp.pdf index 8dbd6c46c3..5d2e418352 100644 Binary files a/assets/slides/08-Recursion_1pp.pdf and b/assets/slides/08-Recursion_1pp.pdf differ diff --git a/assets/slides/09-Tree_Recursion_1pp.pdf b/assets/slides/09-Tree_Recursion_1pp.pdf new file mode 100644 index 0000000000..946dd36b74 Binary files /dev/null and b/assets/slides/09-Tree_Recursion_1pp.pdf differ diff --git a/assets/slides/09.py b/assets/slides/09.py new file mode 100644 index 0000000000..aad8eb3673 --- /dev/null +++ b/assets/slides/09.py @@ -0,0 +1,98 @@ +# Tree Recursion + +# ----------------------- # +# Tracing factorial + +from ucb import trace + +@trace +def fact(n): + """ computes the factorial of n (n!) + >>> fact(5) # 5! = 5 * 4 * 3 * 2 * 1 + 120 + """ + if n == 0 or n == 1: + return 1 + else: + return n * fact(n-1) + +# ----------------------- # +# Mutual Recursion +# (Counting Unique Prime Factors Recursively) +# https://pythontutor.com/render.html#code=def%20smallest_factor%28n%29%3A%0A%20%20%20%20if%20%28n%252%20%3D%3D%200%29%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20k%20%3D%203%0A%20%20%20%20while%20%28k%20%3C%20n%29%3A%0A%20%20%20%20%20%20%20%20if%20%28n%25k%20%3D%3D%200%29%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20k%0A%20%20%20%20%20%20%20%20k%20%2B%3D%201%0A%20%20%20%20return%20n%0A%0A%0Adef%20unique_prime_factors%28n%29%3A%0A%20%20%20%20%22%22%22Return%20the%20number%20of%20unique%20prime%20factors%20of%20n.%0A%0A%20%20%20%20%3E%3E%3E%20unique_prime_factors%2851%29%20%20%23%203%20*%2017%0A%20%20%20%202%0A%20%20%20%20%3E%3E%3E%20unique_prime_factors%2827%29%20%20%20%23%203%20*%203%20*%203%0A%20%20%20%201%0A%20%20%20%20%3E%3E%3E%20unique_prime_factors%28120%29%20%23%202%20*%202%20*%202%20*%203%20*%205%0A%20%20%20%203%0A%20%20%20%20%22%22%22%0A%20%20%20%20k%20%3D%20smallest_factor%28n%29%0A%20%20%20%20def%20no_k%28n%29%3A%0A%20%20%20%20%20%20%20%20%22Return%20the%20number%20of%20unique%20prime%20factors%20of%20n%20other%20than%20k.%22%0A%20%20%20%20%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%20%20%20%20elif%20n%20%25%20k%20!%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20unique_prime_factors%28n%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20no_k%28n//k%29%0A%20%20%20%20return%201%2Bno_k%28n%29%0A%0Aunique_prime_factors%2860%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false +def smallest_factor(n): + if (n%2 == 0): + return 2 + k = 3 + while (k < n): + if (n%k == 0): + return k + k += 1 + return n + + +def unique_prime_factors(n): + """Return the number of unique prime factors of n. + + >>> unique_prime_factors(51) # 3 * 17 + 2 + >>> unique_prime_factors(27) # 3 * 3 * 3 + 1 + >>> unique_prime_factors(120) # 2 * 2 * 2 * 3 * 5 + 3 + """ + k = smallest_factor(n) + def no_k(n): + "Return the number of unique prime factors of n other than k." + if n == 1: + return 0 + elif n % k != 0: + return unique_prime_factors(n) + else: + return no_k(n//k) + return 1+no_k(n) + +unique_prime_factors(120) + +# ----------------------- # +# Count Partitions +# https://pythontutor.com/cp/composingprograms.html#code=def%20count_partitions%28n,%20m%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20elif%20n%20%3C%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20elif%20m%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20with_m%20%3D%20count_partitions%28n-m,%20m%29%20%0A%20%20%20%20%20%20%20%20without_m%20%3D%20count_partitions%28n,%20m-1%29%0A%20%20%20%20%20%20%20%20return%20with_m%20%2B%20without_m%0A%20%20%20%20%20%20%20%20%0Aresult%20%3D%20count_partitions%285,%203%29%0A%0A%23%201%20%2B%201%20%2B%201%20%2B%201%20%2B%201%20%3D%205%0A%23%201%20%2B%201%20%2B%201%20%2B%202%20%2B%20%20%20%3D%205%0A%23%201%20%2B%202%20%2B%202%20%2B%20%20%20%20%20%20%20%3D%205%0A%23%201%20%2B%201%20%2B%203%20%2B%20%20%20%20%20%20%20%3D%205%0A%23%202%20%2B%203%20%2B%20%20%20%20%20%20%20%20%20%20%20%3D%205&cumulative=false&curInstr=0&mode=display&origin=composingprograms.js&py=3&rawInputLstJSON=%5B%5D + +def count_partitions(n, m): + if n == 0: + return 1 + elif n < 0: + return 0 + elif m == 0: + return 0 + else: + with_m = count_partitions(n-m, m) + without_m = count_partitions(n, m-1) + return with_m + without_m + +result = count_partitions(5, 3) + +# 1 + 1 + 1 + 1 + 1 = 5 +# 1 + 1 + 1 + 2 + = 5 +# 1 + 2 + 2 + = 5 +# 1 + 1 + 3 + = 5 +# 2 + 3 + = 5 + +# ----------------------- # + +def count_park(n): + """Count the ways to park cars and motorcycles in n adjacent spots. + >>> count_park(1) # '.' or '%' + 2 + >>> count_park(2) # '..', '.%', '%.', '%%', or '<>' + 5 + >>> count_park(4) # some examples: '<><>', '.%%.', '%<>%', '%.<>' + 29 + """ + if n < 0: + return 0 + elif n == 0: + return 1 + else: + return count_park(n-2) + count_park(n-1) + count_park(n-1) + diff --git a/assets/slides/10-Sequences.pdf b/assets/slides/10-Sequences.pdf new file mode 100644 index 0000000000..a89a700b95 Binary files /dev/null and b/assets/slides/10-Sequences.pdf differ diff --git a/assets/slides/10.py b/assets/slides/10.py new file mode 100644 index 0000000000..edd7486d83 --- /dev/null +++ b/assets/slides/10.py @@ -0,0 +1,110 @@ + +# Lists practice + +digits = [1, 8, 2, 8] +8 in digits +[1, 8] in digits +1 in digits and 8 in digits + +for x in digits: + continue + #print(100 * x) + +def f(x): + for y in [x, x + 1, x + 2]: + print('this is y:', y) + if y > 0: + return y + return 1000 + +def print_negatives(s): + for d in s: + d = -d + print(d) + print(s) + s = [2, 3, 4] + return s + +# Range practice + +def range_practice(): + range(4) + list(range(4)) + range(-2, 2) + list(range(-2, 2)) + range(2, 100000000) # 9 zeroes slows things down a lot + list(range(2, 100000000)) + len(range(2, range(0, 23)[9])) + +def fib(n): + """Return the nth fibonnaci number. + + >>> fib(0) + 0 + >>> fib(2) + 1 + >>> fib(10) + 55 + """ + fib_number = 0 + what_to_add = 1 # to get to the next fib number + for _ in range(n): + what_to_add, fib_number = fib_number, fib_number + what_to_add + return fib_number + +# List comprehension practice + +xs = range(-10, 11) +ys = [x*x - 2*x + 1 for x in xs] + +xs_where_y_is_below_10 = [x for x in xs if x*x - 2*x + 1 < 10] +xs_where_y_is_below_10 = [xs[i] for i in range(len(xs)) if ys[i] < 10] + +# Tree recursion practice + +goal = 21 + +def play(strategy0, strategy1, n=0, who = 0, announce=False): + "Play twenty-one starting at n and return the index of the winner." + strategies = [strategy0, strategy1] + while n < goal: + n = n + strategies[who](n) + if announce: + print('Player', who, 'increases n to', n) + who = 1 - who + return who + +def two_strat(n): + "Always choose 2." + return 2 + +def interactive(n): + "Ask the user." + choice = input('Pick 1, 2, or 3: ') + if choice in ['1', '2', '3']: + return int(choice) + else: + print('Invalid choice!') + return interactive(n) + +def best(n, other_strategy): + """Return an best strategy against other_strategy. + + >>> beat_two_strat = lambda n: best(n, two_strat) + >>> winner(20, beat_two_strat, two_strat) + 1 + >>> winner(19, beat_two_strat, two_strat) + 0 + >>> winner(15, beat_two_strat, two_strat) + 0 + >>> winner(0, beat_two_strat, two_strat) + 0 + """ + plan = lambda future_n: best(future_n, other_strategy) + for choice in range(1, 4): + if play(plan, other_strategy, n + choice, 1) == 0: + return choice + return 1 + +perfect = lambda n: best(n, perfect) + diff --git a/hw/.DS_Store b/hw/.DS_Store new file mode 100644 index 0000000000..efb85e724d Binary files /dev/null and b/hw/.DS_Store differ diff --git a/hw/hw04/hw04.py b/hw/hw04/hw04.py index 83c4b5b59d..14fa401efe 100644 --- a/hw/hw04/hw04.py +++ b/hw/hw04/hw04.py @@ -1,6 +1,3 @@ -LAB_SOURCE_FILE=__file__ - - HW_SOURCE_FILE=__file__ @@ -35,13 +32,13 @@ def digit_distance(n): >>> digit_distance(3) 0 - >>> digit_distance(777) + >>> digit_distance(777) # 0 + 0 0 - >>> digit_distance(314) + >>> digit_distance(314) # 2 + 3 5 - >>> digit_distance(31415926535) + >>> digit_distance(31415926535) # 2 + 3 + 3 + 4 + ... + 2 32 - >>> digit_distance(3464660003) + >>> digit_distance(3464660003) # 1 + 2 + 2 + 2 + ... + 3 16 >>> from construct_check import check >>> # ban all loops diff --git a/hw/hw04/hw04.zip b/hw/hw04/hw04.zip index 96e5f0dd50..0139437b66 100644 Binary files a/hw/hw04/hw04.zip and b/hw/hw04/hw04.zip differ diff --git a/hw/hw04/index.html b/hw/hw04/index.html index e12a89a184..5c8ea537cd 100644 --- a/hw/hw04/index.html +++ b/hw/hw04/index.html @@ -210,9 +210,9 @@

Getting Started Videos

To see these videos, you should be logged into your berkeley.edu email.

-

YouTube link

+

YouTube link

@@ -224,7 +224,7 @@

Q1: Num Eights

Important: Use recursion; the tests will fail if you use any assignment statements or loops. -(You can, however, use function definitions if you'd like.)

+(You can define new functions, but don't put assignment statements there either.)

@@ -272,18 +272,14 @@

Q2: Digit Distance

consecutive digits. For example:

-

Write a function that determines the digit distance of a given positive integer. +

Write a function that determines the digit distance of a positive integer. You must use recursion or the tests will fail.

-

Hint: There are multiple valid ways of solving this problem! -If you're stuck, try writing out an iterative solution -first, and then convert your iterative solution into a recursive one.

-
def digit_distance(n):
@@ -291,13 +287,13 @@ 

Q2: Digit Distance

>>> digit_distance(3) 0 - >>> digit_distance(777) + >>> digit_distance(777) # 0 + 0 0 - >>> digit_distance(314) + >>> digit_distance(314) # 2 + 3 5 - >>> digit_distance(31415926535) + >>> digit_distance(31415926535) # 2 + 3 + 3 + 4 + ... + 2 32 - >>> digit_distance(3464660003) + >>> digit_distance(3464660003) # 1 + 2 + 2 + 2 + ... + 3 16 >>> from construct_check import check >>> # ban all loops @@ -316,8 +312,6 @@

Q2: Digit Distance


-

- @@ -333,7 +327,7 @@

Q3: Interleaved Sum

returns 1 + 2*2 + 3 + 4*4 + 5 = 29.

Important: Implement this function without using any loops or directly testing if a number -is odd or even -- aka modulos (%) are not allowed! Instead of directly checking whether a number +is odd or even (no using %). Instead of directly checking whether a number is even or odd, start with 1, which you know is an odd number.

Hint: Introduce an inner helper function that takes an odd number k and @@ -392,7 +386,7 @@

Submit Assignment

Just For Fun Questions

-

The questions below are out of scope for 61A. You can try them if you want an extra challenge, but they're just puzzles that are not required for the course. Almost all students will skip them, and that's fine. We will not be prioritizing support for these questions on Ed or during Office Hours.

+

The questions below are optional and not representative of exam questions. You can try them if you want an extra challenge, but they're just puzzles that are not required for the course. Almost all students will skip them, and that's fine. We will not be prioritizing support for these questions on Ed or during office hours.

Q4: Towers of Hanoi

diff --git a/hw/hw05/construct_check.py b/hw/hw05/construct_check.py deleted file mode 100644 index bee096e7e4..0000000000 --- a/hw/hw05/construct_check.py +++ /dev/null @@ -1,180 +0,0 @@ -from ast import parse, NodeVisitor, Name - -# For error messages (student-facing) only -_NAMES = { - 'Add': '+', - 'And': 'and', - 'Assert': 'assert', - 'Assign': '=', - 'AnnAssign': '=', - 'AugAssign': 'op=', - 'BitAnd': '&', - 'BitOr': '|', - 'BitXor': '^', - 'Break': 'break', - 'Recursion': 'recursive call', - 'ClassDef': 'class', - 'Continue': 'continue', - 'Del': 'del', - 'Delete': 'delete', - 'Dict': '{...}', - 'DictComp': '{...}', - 'Div': '/', - 'Ellipsis': '...', - 'Eq': '==', - 'ExceptHandler': 'except', - 'ExtSlice': '[::]', - 'FloorDiv': '//', - 'For': 'for', - 'FunctionDef': 'def', - 'Filter': 'filter', - 'GeneratorExp': '(... for ...)', - 'Global': 'global', - 'Gt': '>', - 'GtE': '>=', - 'If': 'if', - 'IfExp': '...if...else...', - 'Import': 'import', - 'ImportFrom': 'from ... import ...', - 'In': 'in', - 'Index': '...[...]', - 'Invert': '~', - 'Is': 'is', - 'IsNot': 'is not ', - 'LShift': '<<', - 'Lambda': 'lambda', - 'List': '[...]', - 'ListComp': '[...for...]', - 'Lt': '<', - 'LtE': '<=', - 'Mod': '%', - 'Mult': '*', - 'NamedExpr': ':=', - 'Nonlocal': 'nonlocal', - 'Not': 'not', - 'NotEq': '!=', - 'NotIn': 'not in', - 'Or': 'or', - 'Pass': 'pass', - 'Pow': '**', - 'RShift': '>>', - 'Raise': 'raise', - 'Return': 'return', - 'Set': '{ ... } (set)', - 'SetComp': '{ ... for ... } (set)', - 'Slice': '[ : ]', - 'Starred': '', - 'Str': 'str', - 'Sub': '-', - 'Subscript': '[]', - 'Try': 'try', - 'Tuple': '(... , ... )', - 'UAdd': '+', - 'USub': '-', - 'While': 'while', - 'With': 'with', - 'Yield': 'yield', - 'YieldFrom': 'yield from', -} - -def check(source_file, checked_funcs, disallow, source=None): - """Checks that AST nodes whose type names are present in DISALLOW - (an object supporting 'in') are not present in the function(s) named - CHECKED_FUNCS in SOURCE. By default, SOURCE is the contents of the - file SOURCE_FILE. CHECKED_FUNCS is either a string (indicating a single - name) or an object of some other type that supports 'in'. CHECKED_FUNCS - may contain __main__ to indicate an entire module. Prints reports of - each prohibited node and returns True iff none are found. - See ast.__dir__() for AST type names. The special node name 'Recursion' - checks for overtly recursive calls (i.e., calls of the form NAME(...) where - NAME is an enclosing def.""" - return ExclusionChecker(disallow).check(source_file, checked_funcs, source) - -class ExclusionChecker(NodeVisitor): - """An AST visitor that checks that certain constructs are excluded from - parts of a program. ExclusionChecker(EXC) checks that AST node types - whose names are in the sequence or set EXC are not present. Its check - method visits nodes in a given function of a source file checking that the - indicated node types are not used.""" - - def __init__(self, disallow=()): - """DISALLOW is the initial default list of disallowed - node-type names.""" - self._disallow = set(disallow) - self._checking = False - self._errs = 0 - - def generic_visit(self, node): - if self._checking and type(node).__name__ in self._disallow: - self._report(node) - super().generic_visit(node) - - def visit_Module(self, node): - if "__main__" in self._checked_funcs: - self._checking = True - self._checked_name = self._source_file - super().generic_visit(node) - - def visit_Call(self, node): - if 'Recursion' in self._disallow and \ - type(node.func) is Name and \ - node.func.id in self._func_nest: - self._report(node, "should not be recursive") - self.generic_visit(node) - - def visit_FunctionDef(self, node): - self._func_nest.append(node.name) - if self._checking: - self.generic_visit(node) - elif node.name in self._checked_funcs: - self._checked_name = "Function " + node.name - checking0 = self._checking - self._checking = True - super().generic_visit(node) - self._checking = checking0 - self._func_nest.pop() - - def _report(self, node, msg=None): - node_name = _NAMES.get(type(node).__name__, type(node).__name__) - if msg is None: - msg = "should not contain '{}'".format(node_name) - print("{} {}".format(self._checked_name, msg)) - self._errs += 1 - - def errors(self): - """Returns the number of number of prohibited constructs found in - the last call to check.""" - return self._errs - - def check(self, source_file, checked_funcs, disallow=None, source=None): - """Checks that AST nodes whose type names are present in DISALLOW - (an object supporting the contains test) are not present in - the function(s) named CHECKED_FUNCS in SOURCE. By default, SOURCE - is the contents of the file SOURCE_FILE. DISALLOW defaults to the - argument given to the constructor (and resets that value if it is - present). CHECKED_FUNCS is either a string (indicating a single - name) or an object of some other type that supports 'in'. - CHECKED_FUNCS may contain __main__ to indicate an entire module. - Prints reports of each prohibited node and returns True iff none - are found. - See ast.__dir__() for AST type names. The special node name - 'Recursion' checks for overtly recursive calls (i.e., calls of the - form NAME(...) where NAME is an enclosing def.""" - - self._checking = False - self._source_file = source_file - self._func_nest = [] - if type(checked_funcs) is str: - self._checked_funcs = { checked_funcs } - else: - self._checked_funcs = set(checked_funcs) - if disallow is not None: - self._disallow = set(disallow) - if source is None: - with open(source_file, 'r', errors='ignore') as inp: - source = inp.read() - p = parse(source, source_file) - self._errs = 0 - - self.visit(p) - return self._errs == 0 \ No newline at end of file diff --git a/hw/hw05/hw05.ok b/hw/hw05/hw05.ok deleted file mode 100644 index 7563437b1c..0000000000 --- a/hw/hw05/hw05.ok +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Homework 5", - "endpoint": "cal/cs61a/fa24/hw05", - "src": [ - "hw05.py" - ], - "tests": { - "hw*.py": "doctest", - "tests/*.py": "ok_test" - }, - "default_tests": [ - "hailstone", - "merge", - "yield_paths" - ], - "protocols": [ - "restore", - "file_contents", - "analytics", - "help", - "unlock", - "grading", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw05/hw05.py b/hw/hw05/hw05.py deleted file mode 100644 index 02c48e0d06..0000000000 --- a/hw/hw05/hw05.py +++ /dev/null @@ -1,135 +0,0 @@ -def hailstone(n): - """Q1: Yields the elements of the hailstone sequence starting at n. - At the end of the sequence, yield 1 infinitely. - - >>> hail_gen = hailstone(10) - >>> [next(hail_gen) for _ in range(10)] - [10, 5, 16, 8, 4, 2, 1, 1, 1, 1] - >>> next(hail_gen) - 1 - """ - "*** YOUR CODE HERE ***" - - -def merge(a, b): - """Q2: - >>> def sequence(start, step): - ... while True: - ... yield start - ... start += step - >>> a = sequence(2, 3) # 2, 5, 8, 11, 14, ... - >>> b = sequence(3, 2) # 3, 5, 7, 9, 11, 13, 15, ... - >>> result = merge(a, b) # 2, 3, 5, 7, 8, 9, 11, 13, 14, 15 - >>> [next(result) for _ in range(10)] - [2, 3, 5, 7, 8, 9, 11, 13, 14, 15] - """ - "*** YOUR CODE HERE ***" - - -def yield_paths(t, value): - """Q4: Yields all possible paths from the root of t to a node with the label - value as a list. - - >>> t1 = tree(1, [tree(2, [tree(3), tree(4, [tree(6)]), tree(5)]), tree(5)]) - >>> print_tree(t1) - 1 - 2 - 3 - 4 - 6 - 5 - 5 - >>> next(yield_paths(t1, 6)) - [1, 2, 4, 6] - >>> path_to_5 = yield_paths(t1, 5) - >>> sorted(list(path_to_5)) - [[1, 2, 5], [1, 5]] - - >>> t2 = tree(0, [tree(2, [t1])]) - >>> print_tree(t2) - 0 - 2 - 1 - 2 - 3 - 4 - 6 - 5 - 5 - >>> path_to_2 = yield_paths(t2, 2) - >>> sorted(list(path_to_2)) - [[0, 2], [0, 2, 1, 2]] - """ - if label(t) == value: - yield ____ - for b in branches(t): - for ____ in ____: - yield ____ - - - -# Tree Data Abstraction - -def tree(label, branches=[]): - """Construct a tree with the given label value and a list of branches.""" - for branch in branches: - assert is_tree(branch), 'branches must be trees' - return [label] + list(branches) - -def label(tree): - """Return the label value of a tree.""" - return tree[0] - -def branches(tree): - """Return the list of branches of the given tree.""" - return tree[1:] - -def is_tree(tree): - """Returns True if the given tree is a tree, and False otherwise.""" - if type(tree) != list or len(tree) < 1: - return False - for branch in branches(tree): - if not is_tree(branch): - return False - return True - -def is_leaf(tree): - """Returns True if the given tree's list of branches is empty, and False - otherwise. - """ - return not branches(tree) - -def print_tree(t, indent=0): - """Print a representation of this tree in which each node is - indented by two spaces times its depth from the root. - - >>> print_tree(tree(1)) - 1 - >>> print_tree(tree(1, [tree(2)])) - 1 - 2 - >>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])]) - >>> print_tree(numbers) - 1 - 2 - 3 - 4 - 5 - 6 - 7 - """ - print(' ' * indent + str(label(t))) - for b in branches(t): - print_tree(b, indent + 1) - -def copy_tree(t): - """Returns a copy of t. Only for testing purposes. - - >>> t = tree(5) - >>> copy = copy_tree(t) - >>> t = tree(6) - >>> print_tree(copy) - 5 - """ - return tree(label(t), [copy_tree(b) for b in branches(t)]) - diff --git a/hw/hw05/hw05.zip b/hw/hw05/hw05.zip deleted file mode 100644 index 48fbd8e204..0000000000 Binary files a/hw/hw05/hw05.zip and /dev/null differ diff --git a/hw/hw05/index.html b/hw/hw05/index.html deleted file mode 100644 index f3bf96302b..0000000000 --- a/hw/hw05/index.html +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 5 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 5: Generators - - - - - - -

-
- - -

Due by 11:59pm on Thursday, October 17

- - - - - -

Instructions

- -

Download hw05.zip. Inside the archive, you will find a file called -hw05.py, along with a copy of the ok autograder.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - -

Readings: You might find the following references - useful:

- - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -

Required Questions

- - -
- - - -
- -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

-
- - -

Q1: Infinite Hailstone

- - -

Write a generator function that yields the elements of the hailstone sequence starting at number n. -After reaching the end of the hailstone sequence, the generator should yield the value 1 indefinitely.

- -

Here's a quick reminder of how the hailstone sequence is defined:

- -
    -
  1. Pick a positive integer n as the start.
  2. -
  3. If n is even, divide it by 2.
  4. -
  5. If n is odd, multiply it by 3 and add 1.
  6. -
  7. Continue this process until n is 1.
  8. -
- -

Try to write this generator function recursively. If you're stuck, you can first try writing it iteratively -and then seeing how you can turn that implementation into a recursive one.

- -

Hint: Since hailstone returns a generator, you can yield from a call to hailstone!

- - - -
def hailstone(n):
-    """Q1: Yields the elements of the hailstone sequence starting at n.
-       At the end of the sequence, yield 1 infinitely.
-
-    >>> hail_gen = hailstone(10)
-    >>> [next(hail_gen) for _ in range(10)]
-    [10, 5, 16, 8, 4, 2, 1, 1, 1, 1]
-    >>> next(hail_gen)
-    1
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q hailstone
- -
- - -

Q2: Merge

- -

Write a generator function merge that takes in two infinite generators a and b that are in increasing order without duplicates and returns a generator that has all the elements of both generators, in increasing order, without duplicates.

- - - -
def merge(a, b):
-    """Q2:
-    >>> def sequence(start, step):
-    ...     while True:
-    ...         yield start
-    ...         start += step
-    >>> a = sequence(2, 3) # 2, 5, 8, 11, 14, ...
-    >>> b = sequence(3, 2) # 3, 5, 7, 9, 11, 13, 15, ...
-    >>> result = merge(a, b) # 2, 3, 5, 7, 8, 9, 11, 13, 14, 15
-    >>> [next(result) for _ in range(10)]
-    [2, 3, 5, 7, 8, 9, 11, 13, 14, 15]
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q merge
- -
- - -

Q3: Yield Paths

- - -

Define a generator function yield_paths which takes in a tree t, a value -value, and returns a generator object which yields each path from the root -of t to a node that has label value.

- -

Each path should be represented as a list of the labels along that path in the -tree. You may yield the paths in any order.

- -
def yield_paths(t, value):
-    """Q4: Yields all possible paths from the root of t to a node with the label
-    value as a list.
-
-    >>> t1 = tree(1, [tree(2, [tree(3), tree(4, [tree(6)]), tree(5)]), tree(5)])
-    >>> print_tree(t1)
-    1
-      2
-        3
-        4
-          6
-        5
-      5
-    >>> next(yield_paths(t1, 6))
-    [1, 2, 4, 6]
-    >>> path_to_5 = yield_paths(t1, 5)
-    >>> sorted(list(path_to_5))
-    [[1, 2, 5], [1, 5]]
-
-    >>> t2 = tree(0, [tree(2, [t1])])
-    >>> print_tree(t2)
-    0
-      2
-        1
-          2
-            3
-            4
-              6
-            5
-          5
-    >>> path_to_2 = yield_paths(t2, 2)
-    >>> sorted(list(path_to_2))
-    [[0, 2], [0, 2, 1, 2]]
-    """
-    if label(t) == value:
-        yield ____
-    for b in branches(t):
-        for ____ in ____:
-            yield ____
-
- -

Hint: If you're having trouble getting started, think about how you'd approach this -problem if it wasn't a generator function. What would your recursive calls be? -With a generator function, what happens if you make a "recursive call" within its body?

- - - -

Hint: Try coming up with a few simple cases of your own! How should this function work when t is a leaf node?

- - - -

Hint: Remember, it's possible to loop over generator objects because generators are iterators!

- - - -

Note: Remember that this problem should yield paths -- do not return a list of paths!

- - - -

Use Ok to test your code:

python3 ok -q yield_paths
- -
- - - - -

Check Your Score Locally

- -

You can locally check your score on each question of this assignment by running

- -
python3 ok --score
- -

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

- - -

Submit Assignment

- - -

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

- - -

Exam Practice

- - -

Homework assignments will also contain prior exam questions for you to try. -These questions have no submission component; feel free to attempt them if you'd like some practice!

- -
    -
  1. Summer 2018 Final Q7a,b: Streams and Jennyrators
  2. -
  3. Spring 2019 Final Q1: Iterators are inevitable
  4. -
  5. Spring 2021 MT2 Q8: The Tree of L-I-F-E
  6. -
  7. Summer 2016 Final Q8: Zhen-erators Produce Power
  8. -
  9. Spring 2018 Final Q4a: Apply Yourself
  10. -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw06/construct_check.py b/hw/hw06/construct_check.py deleted file mode 100644 index bee096e7e4..0000000000 --- a/hw/hw06/construct_check.py +++ /dev/null @@ -1,180 +0,0 @@ -from ast import parse, NodeVisitor, Name - -# For error messages (student-facing) only -_NAMES = { - 'Add': '+', - 'And': 'and', - 'Assert': 'assert', - 'Assign': '=', - 'AnnAssign': '=', - 'AugAssign': 'op=', - 'BitAnd': '&', - 'BitOr': '|', - 'BitXor': '^', - 'Break': 'break', - 'Recursion': 'recursive call', - 'ClassDef': 'class', - 'Continue': 'continue', - 'Del': 'del', - 'Delete': 'delete', - 'Dict': '{...}', - 'DictComp': '{...}', - 'Div': '/', - 'Ellipsis': '...', - 'Eq': '==', - 'ExceptHandler': 'except', - 'ExtSlice': '[::]', - 'FloorDiv': '//', - 'For': 'for', - 'FunctionDef': 'def', - 'Filter': 'filter', - 'GeneratorExp': '(... for ...)', - 'Global': 'global', - 'Gt': '>', - 'GtE': '>=', - 'If': 'if', - 'IfExp': '...if...else...', - 'Import': 'import', - 'ImportFrom': 'from ... import ...', - 'In': 'in', - 'Index': '...[...]', - 'Invert': '~', - 'Is': 'is', - 'IsNot': 'is not ', - 'LShift': '<<', - 'Lambda': 'lambda', - 'List': '[...]', - 'ListComp': '[...for...]', - 'Lt': '<', - 'LtE': '<=', - 'Mod': '%', - 'Mult': '*', - 'NamedExpr': ':=', - 'Nonlocal': 'nonlocal', - 'Not': 'not', - 'NotEq': '!=', - 'NotIn': 'not in', - 'Or': 'or', - 'Pass': 'pass', - 'Pow': '**', - 'RShift': '>>', - 'Raise': 'raise', - 'Return': 'return', - 'Set': '{ ... } (set)', - 'SetComp': '{ ... for ... } (set)', - 'Slice': '[ : ]', - 'Starred': '', - 'Str': 'str', - 'Sub': '-', - 'Subscript': '[]', - 'Try': 'try', - 'Tuple': '(... , ... )', - 'UAdd': '+', - 'USub': '-', - 'While': 'while', - 'With': 'with', - 'Yield': 'yield', - 'YieldFrom': 'yield from', -} - -def check(source_file, checked_funcs, disallow, source=None): - """Checks that AST nodes whose type names are present in DISALLOW - (an object supporting 'in') are not present in the function(s) named - CHECKED_FUNCS in SOURCE. By default, SOURCE is the contents of the - file SOURCE_FILE. CHECKED_FUNCS is either a string (indicating a single - name) or an object of some other type that supports 'in'. CHECKED_FUNCS - may contain __main__ to indicate an entire module. Prints reports of - each prohibited node and returns True iff none are found. - See ast.__dir__() for AST type names. The special node name 'Recursion' - checks for overtly recursive calls (i.e., calls of the form NAME(...) where - NAME is an enclosing def.""" - return ExclusionChecker(disallow).check(source_file, checked_funcs, source) - -class ExclusionChecker(NodeVisitor): - """An AST visitor that checks that certain constructs are excluded from - parts of a program. ExclusionChecker(EXC) checks that AST node types - whose names are in the sequence or set EXC are not present. Its check - method visits nodes in a given function of a source file checking that the - indicated node types are not used.""" - - def __init__(self, disallow=()): - """DISALLOW is the initial default list of disallowed - node-type names.""" - self._disallow = set(disallow) - self._checking = False - self._errs = 0 - - def generic_visit(self, node): - if self._checking and type(node).__name__ in self._disallow: - self._report(node) - super().generic_visit(node) - - def visit_Module(self, node): - if "__main__" in self._checked_funcs: - self._checking = True - self._checked_name = self._source_file - super().generic_visit(node) - - def visit_Call(self, node): - if 'Recursion' in self._disallow and \ - type(node.func) is Name and \ - node.func.id in self._func_nest: - self._report(node, "should not be recursive") - self.generic_visit(node) - - def visit_FunctionDef(self, node): - self._func_nest.append(node.name) - if self._checking: - self.generic_visit(node) - elif node.name in self._checked_funcs: - self._checked_name = "Function " + node.name - checking0 = self._checking - self._checking = True - super().generic_visit(node) - self._checking = checking0 - self._func_nest.pop() - - def _report(self, node, msg=None): - node_name = _NAMES.get(type(node).__name__, type(node).__name__) - if msg is None: - msg = "should not contain '{}'".format(node_name) - print("{} {}".format(self._checked_name, msg)) - self._errs += 1 - - def errors(self): - """Returns the number of number of prohibited constructs found in - the last call to check.""" - return self._errs - - def check(self, source_file, checked_funcs, disallow=None, source=None): - """Checks that AST nodes whose type names are present in DISALLOW - (an object supporting the contains test) are not present in - the function(s) named CHECKED_FUNCS in SOURCE. By default, SOURCE - is the contents of the file SOURCE_FILE. DISALLOW defaults to the - argument given to the constructor (and resets that value if it is - present). CHECKED_FUNCS is either a string (indicating a single - name) or an object of some other type that supports 'in'. - CHECKED_FUNCS may contain __main__ to indicate an entire module. - Prints reports of each prohibited node and returns True iff none - are found. - See ast.__dir__() for AST type names. The special node name - 'Recursion' checks for overtly recursive calls (i.e., calls of the - form NAME(...) where NAME is an enclosing def.""" - - self._checking = False - self._source_file = source_file - self._func_nest = [] - if type(checked_funcs) is str: - self._checked_funcs = { checked_funcs } - else: - self._checked_funcs = set(checked_funcs) - if disallow is not None: - self._disallow = set(disallow) - if source is None: - with open(source_file, 'r', errors='ignore') as inp: - source = inp.read() - p = parse(source, source_file) - self._errs = 0 - - self.visit(p) - return self._errs == 0 \ No newline at end of file diff --git a/hw/hw06/hw06.py b/hw/hw06/hw06.py deleted file mode 100644 index 036e01e76c..0000000000 --- a/hw/hw06/hw06.py +++ /dev/null @@ -1,156 +0,0 @@ -passphrase = 'REPLACE_THIS_WITH_PASSPHRASE' - -def midsem_survey(p): - """ - You do not need to understand this code. - >>> midsem_survey(passphrase) - 'c20d4e5854c4c9cdfd14626aad39bd5a1e2ed9bb30dca56d5643a3ad' - """ - import hashlib - return hashlib.sha224(p.encode('utf-8')).hexdigest() - - -class VendingMachine: - """A vending machine that vends some product for some price. - - >>> v = VendingMachine('candy', 10) - >>> v.vend() - 'Nothing left to vend. Please restock.' - >>> v.add_funds(15) - 'Nothing left to vend. Please restock. Here is your $15.' - >>> v.restock(2) - 'Current candy stock: 2' - >>> v.vend() - 'Please add $10 more funds.' - >>> v.add_funds(7) - 'Current balance: $7' - >>> v.vend() - 'Please add $3 more funds.' - >>> v.add_funds(5) - 'Current balance: $12' - >>> v.vend() - 'Here is your candy and $2 change.' - >>> v.add_funds(10) - 'Current balance: $10' - >>> v.vend() - 'Here is your candy.' - >>> v.add_funds(15) - 'Nothing left to vend. Please restock. Here is your $15.' - - >>> w = VendingMachine('soda', 2) - >>> w.restock(3) - 'Current soda stock: 3' - >>> w.restock(3) - 'Current soda stock: 6' - >>> w.add_funds(2) - 'Current balance: $2' - >>> w.vend() - 'Here is your soda.' - """ - "*** YOUR CODE HERE ***" - - -def store_digits(n): - """Stores the digits of a positive number n in a linked list. - - >>> s = store_digits(1) - >>> s - Link(1) - >>> store_digits(2345) - Link(2, Link(3, Link(4, Link(5)))) - >>> store_digits(876) - Link(8, Link(7, Link(6))) - >>> store_digits(2450) - Link(2, Link(4, Link(5, Link(0)))) - >>> # a check for restricted functions - >>> import inspect, re - >>> cleaned = re.sub(r"#.*\\n", '', re.sub(r'"{3}[\s\S]*?"{3}', '', inspect.getsource(store_digits))) - >>> print("Do not use str or reversed!") if any([r in cleaned for r in ["str", "reversed"]]) else None - """ - "*** YOUR CODE HERE ***" - - -def deep_map_mut(func, lnk): - """Mutates a deep link lnk by replacing each item found with the - result of calling func on the item. Does NOT create new Links (so - no use of Link's constructor). - - Does not return the modified Link object. - - >>> link1 = Link(3, Link(Link(4), Link(5, Link(6)))) - >>> print(link1) - <3 <4> 5 6> - >>> # Disallow the use of making new Links before calling deep_map_mut - >>> Link.__init__, hold = lambda *args: print("Do not create any new Links."), Link.__init__ - >>> try: - ... deep_map_mut(lambda x: x * x, link1) - ... finally: - ... Link.__init__ = hold - >>> print(link1) - <9 <16> 25 36> - """ - "*** YOUR CODE HERE ***" - - -def two_list(vals, counts): - """ - Returns a linked list according to the two lists that were passed in. Assume - vals and counts are the same size. Elements in vals represent the value, and the - corresponding element in counts represents the number of this value desired in the - final linked list. Assume all elements in counts are greater than 0. Assume both - lists have at least one element. - >>> a = [1, 3] - >>> b = [1, 1] - >>> c = two_list(a, b) - >>> c - Link(1, Link(3)) - >>> a = [1, 3, 2] - >>> b = [2, 2, 1] - >>> c = two_list(a, b) - >>> c - Link(1, Link(1, Link(3, Link(3, Link(2))))) - """ - "*** YOUR CODE HERE ***" - - -class Link: - """A linked list. - - >>> s = Link(1) - >>> s.first - 1 - >>> s.rest is Link.empty - True - >>> s = Link(2, Link(3, Link(4))) - >>> s.first = 5 - >>> s.rest.first = 6 - >>> s.rest.rest = Link.empty - >>> s # Displays the contents of repr(s) - Link(5, Link(6)) - >>> s.rest = Link(7, Link(Link(8, Link(9)))) - >>> s - Link(5, Link(7, Link(Link(8, Link(9))))) - >>> print(s) # Prints str(s) - <5 7 <8 9>> - """ - empty = () - - def __init__(self, first, rest=empty): - assert rest is Link.empty or isinstance(rest, Link) - self.first = first - self.rest = rest - - def __repr__(self): - if self.rest is not Link.empty: - rest_repr = ', ' + repr(self.rest) - else: - rest_repr = '' - return 'Link(' + repr(self.first) + rest_repr + ')' - - def __str__(self): - string = '<' - while self.rest is not Link.empty: - string += str(self.first) + ' ' - self = self.rest - return string + str(self.first) + '>' - diff --git a/hw/hw06/hw06.scm b/hw/hw06/hw06.scm deleted file mode 100644 index 71f1719ebb..0000000000 --- a/hw/hw06/hw06.scm +++ /dev/null @@ -1,42 +0,0 @@ -(define (square n) (* n n)) - -(define (pow base exp) 'YOUR-CODE-HERE) - -(define (repeatedly-cube n x) - (if (zero? n) - x - (let (_________________) - (* y y y)))) - -(define (cddr s) (cdr (cdr s))) - -(define (cadr s) 'YOUR-CODE-HERE) - -(define (caddr s) 'YOUR-CODE-HERE) - -(define (ascending? s) 'YOUR-CODE-HERE) - -(define (my-filter pred s) 'YOUR-CODE-HERE) - -(define (no-repeats s) 'YOUR-CODE-HERE) - -; helper function -; returns the values of lst that are bigger than x -; e.g., (larger-values 3 '(1 2 3 4 5 1 2 3 4 5)) --> (4 5 4 5) -(define (larger-values x lst) - ______________________________________________) - -(define (longest-increasing-subsequence lst) - (if (null? lst) - nil - (begin (define first (car lst)) - (define rest (cdr lst)) - (define large-values-rest - (larger-values first rest)) - (define with-first - ______________________________________________) - (define without-first - ______________________________________________) - (if ______________________________________________ - with-first - without-first)))) diff --git a/hw/hw06/hw06.zip b/hw/hw06/hw06.zip deleted file mode 100644 index 8d4299ed9e..0000000000 Binary files a/hw/hw06/hw06.zip and /dev/null differ diff --git a/hw/hw06/index.html b/hw/hw06/index.html deleted file mode 100644 index 316aa54e55..0000000000 --- a/hw/hw06/index.html +++ /dev/null @@ -1,629 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 6 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 6: OOP, Linked Lists - - - - - - -

-
- - -

Due by 11:59pm on Thursday, October 24

- - - - - -

Instructions

- -

Download hw06.zip. Inside the archive, you will find a file called -hw06.py, along with a copy of the ok autograder.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -

Required Questions

- - -
- - -
- -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

-
- - -

Midsemester Survey

- - - -

Q1: Mid-Semester Feedback

- - -

As part of this assignment, fill out the -Mid-Semester Feedback form.

- -

Confidentiality: -Your responses to the survey are confidential, and only the instructors -will be able to see this data unanonymized. -More specifics on confidentiality can be found on the survey itself.

- -

Once you finish the survey, you will be presented with a passphrase (if you miss -it, it should also be at the bottom of the confirmation email you receive). Put -this passphrase, as a string, on the line that says -passphrase = 'REPLACE_THIS_WITH_PASSPHRASE' in the Python file for this assignment. -E.g. if the passphrase is abc, then the line should be passphrase = 'abc'.

- -

Use Ok to test your code:

python3 ok -q midsem_survey
- -
- - -

OOP

- - -

Q2: Vending Machine

- - -

In this question you'll create a vending machine that sells a single product and provides change when needed.

- -

Create a class called VendingMachine that represents a vending -machine for some product. A VendingMachine object returns strings -describing its interactions. Make sure your output exactly matches the strings in the doctests including punctuation and spacing!

- -

You may find Python's formatted string literals, or f-strings useful. -A quick example:

- -
>>> feeling = 'love'
->>> course = '61A!'
->>> f'I {feeling} {course}'
-'I love 61A!'
- -

Fill in the VendingMachine class, adding attributes and methods as appropriate, such that its behavior matches the following doctests:

- - - -
class VendingMachine:
-    """A vending machine that vends some product for some price.
-
-    >>> v = VendingMachine('candy', 10)
-    >>> v.vend()
-    'Nothing left to vend. Please restock.'
-    >>> v.add_funds(15)
-    'Nothing left to vend. Please restock. Here is your $15.'
-    >>> v.restock(2)
-    'Current candy stock: 2'
-    >>> v.vend()
-    'Please add $10 more funds.'
-    >>> v.add_funds(7)
-    'Current balance: $7'
-    >>> v.vend()
-    'Please add $3 more funds.'
-    >>> v.add_funds(5)
-    'Current balance: $12'
-    >>> v.vend()
-    'Here is your candy and $2 change.'
-    >>> v.add_funds(10)
-    'Current balance: $10'
-    >>> v.vend()
-    'Here is your candy.'
-    >>> v.add_funds(15)
-    'Nothing left to vend. Please restock. Here is your $15.'
-
-    >>> w = VendingMachine('soda', 2)
-    >>> w.restock(3)
-    'Current soda stock: 3'
-    >>> w.restock(3)
-    'Current soda stock: 6'
-    >>> w.add_funds(2)
-    'Current balance: $2'
-    >>> w.vend()
-    'Here is your soda.'
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q VendingMachine
- -
- - - - -

Check Your Score Locally

- -

You can locally check your score on each question of this assignment by running

- -
python3 ok --score
- -

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

- -

Submit Assignment

- - -

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

- - -

Optional Questions

- - -

Q3: Store Digits

- - -

Write a function store_digits that takes in an integer n and returns -a linked list where each element of the list is a digit of n.

- -

Important: Do not use any string manipulation functions like str and reversed.

- - - -
def store_digits(n):
-    """Stores the digits of a positive number n in a linked list.
-
-    >>> s = store_digits(1)
-    >>> s
-    Link(1)
-    >>> store_digits(2345)
-    Link(2, Link(3, Link(4, Link(5))))
-    >>> store_digits(876)
-    Link(8, Link(7, Link(6)))
-    >>> store_digits(2450)
-    Link(2, Link(4, Link(5, Link(0))))
-    >>> # a check for restricted functions
-    >>> import inspect, re
-    >>> cleaned = re.sub(r"#.*\\n", '', re.sub(r'"{3}[\s\S]*?"{3}', '', inspect.getsource(store_digits)))
-    >>> print("Do not use str or reversed!") if any([r in cleaned for r in ["str", "reversed"]]) else None
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q store_digits
- -
- - -

Q4: Mutable Mapping

- - -

Implement deep_map_mut(func, link), which applies a function func onto -all elements in the given linked list lnk. If an element is itself a -linked list, apply func to each of its elements, and so on.

- -

Your implementation should mutate the original linked list. Do not -create any new linked lists.

- -

Hint: The built-in isinstance function may be useful.

- -
>>> s = Link(1, Link(2, Link(3, Link(4))))
->>> isinstance(s, Link)
-True
->>> isinstance(s, int)
-False
- - - -

Construct Check: The last doctest of this question ensures that you -do not create new linked lists. If you are failing this doctest, ensure -that you are not creating link lists by calling the constructor, i.e.

- -
s = Link(1)
- - - -
def deep_map_mut(func, lnk):
-    """Mutates a deep link lnk by replacing each item found with the
-    result of calling func on the item. Does NOT create new Links (so
-    no use of Link's constructor).
-
-    Does not return the modified Link object.
-
-    >>> link1 = Link(3, Link(Link(4), Link(5, Link(6))))
-    >>> print(link1)
-    <3 <4> 5 6>
-    >>> # Disallow the use of making new Links before calling deep_map_mut
-    >>> Link.__init__, hold = lambda *args: print("Do not create any new Links."), Link.__init__
-    >>> try:
-    ...     deep_map_mut(lambda x: x * x, link1)
-    ... finally:
-    ...     Link.__init__ = hold
-    >>> print(link1)
-    <9 <16> 25 36>
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q deep_map_mut
- -
- - -

Q5: Two List

- - -

Implement a function two_list that takes in two lists and returns a linked list. The first list contains the -values that we want to put in the linked list, and the second list contains the number of each corresponding value. -Assume both lists are the same size and have a length of 1 or greater. Assume all elements in the second list -are greater than 0.

- - - -
def two_list(vals, counts):
-    """
-    Returns a linked list according to the two lists that were passed in. Assume
-    vals and counts are the same size. Elements in vals represent the value, and the
-    corresponding element in counts represents the number of this value desired in the
-    final linked list. Assume all elements in counts are greater than 0. Assume both
-    lists have at least one element.
-    >>> a = [1, 3]
-    >>> b = [1, 1]
-    >>> c = two_list(a, b)
-    >>> c
-    Link(1, Link(3))
-    >>> a = [1, 3, 2]
-    >>> b = [2, 2, 1]
-    >>> c = two_list(a, b)
-    >>> c
-    Link(1, Link(1, Link(3, Link(3, Link(2)))))
-    """
-    "*** YOUR CODE HERE ***"
-
- -
- -

Use Ok to test your code:

python3 ok -q two_list
- -
- - -

Exam Practice

- -

Homework assignments will also contain prior exam questions for you to try. -These questions have no submission component; feel free to attempt them if you'd like some practice!

- -

Object-Oriented Programming

- -
    -
  1. Spring 2022 MT2 Q8: CS61A Presents The Game of Hoop.
  2. -
  3. Fall 2020 MT2 Q3: Sparse Lists
  4. -
  5. Fall 2019 MT2 Q7: Version 2.0
  6. -
- -

Linked Lists

- -
    -
  1. Fall 2020 Final Q3: College Party
  2. -
  3. Fall 2018 MT2 Q6: Dr. Frankenlink
  4. -
  5. Spring 2017 MT1 Q5: Insert
  6. -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw06/ok b/hw/hw06/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw06/ok and /dev/null differ diff --git a/hw/hw06/scheme b/hw/hw06/scheme deleted file mode 100644 index 346c9b5fa7..0000000000 Binary files a/hw/hw06/scheme and /dev/null differ diff --git a/hw/hw06/tests/ascending.py b/hw/hw06/tests/ascending.py deleted file mode 100644 index 4579c4522c..0000000000 --- a/hw/hw06/tests/ascending.py +++ /dev/null @@ -1,66 +0,0 @@ -test = { - 'name': 'ascending?', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (ascending? '(1 2 3 4 5)) ; #t or #f - dace58f74ad189c312b83d448006241f - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(1 5 2 4 3)) ; #t or #f - 43c81514c1a0caaf669929b6e656c76c - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(2 2)) ; #t or #f - dace58f74ad189c312b83d448006241f - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(1 2 2 4 3)) ; #t or #f - 43c81514c1a0caaf669929b6e656c76c - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '()) ; #t or #f - dace58f74ad189c312b83d448006241f - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/cadr-caddr.py b/hw/hw06/tests/cadr-caddr.py deleted file mode 100644 index 6d1ca8d194..0000000000 --- a/hw/hw06/tests/cadr-caddr.py +++ /dev/null @@ -1,43 +0,0 @@ -test = { - 'name': 'cadr-caddr', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (cddr '(1 2 3 4)) - (3 4) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (cadr '(1 2 3 4)) - 2 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (caddr '(1 2 3 4)) - 3 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/filter.py b/hw/hw06/tests/filter.py deleted file mode 100644 index 74bc1aff49..0000000000 --- a/hw/hw06/tests/filter.py +++ /dev/null @@ -1,87 +0,0 @@ -test = { - 'name': 'my-filter', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (my-filter even? '(1 2 3 4)) - 18ed436675247bac3aee01a3103ea649 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? '(1 3 5)) - 4cc9884dfb545fbb2d98f3843fec6a4a - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? '(2 4 6 1)) - e7b3891c5a7d2f503188f1818ec702da - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter even? '(3)) - d17487605f66346bf68b6fb7c92f6257 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? nil) - d17487605f66346bf68b6fb7c92f6257 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - }, - { - 'cases': [ - { - 'code': r""" - scm> (my-filter even? '(1 2 3 4)) ; checks you dont use builtin filter - 18ed436675247bac3aee01a3103ea649 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (define filter nil) - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/longest-increasing-subsequence.py b/hw/hw06/tests/longest-increasing-subsequence.py deleted file mode 100644 index 0263b61d84..0000000000 --- a/hw/hw06/tests/longest-increasing-subsequence.py +++ /dev/null @@ -1,37 +0,0 @@ -test = { - 'name': 'longest-increasing-subsequence', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (longest-increasing-subsequence '()) - () - scm> (longest-increasing-subsequence '(1)) - (1) - scm> (longest-increasing-subsequence '(1 2 3)) - (1 2 3) - scm> (longest-increasing-subsequence '(1 9 2 3)) - (1 2 3) - scm> (longest-increasing-subsequence '(1 9 8 7 6 5 4 3 2 3)) - (1 2 3) - scm> (longest-increasing-subsequence '(1 9 8 7 2 3 6 5 4 5)) - (1 2 3 4 5) - scm> (longest-increasing-subsequence '(1 2 3 4 9 3 4 1 10 5)) - (1 2 3 4 9 10) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/no_repeats.py b/hw/hw06/tests/no_repeats.py deleted file mode 100644 index 908613a788..0000000000 --- a/hw/hw06/tests/no_repeats.py +++ /dev/null @@ -1,93 +0,0 @@ -test = { - 'name': 'no-repeats', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (no-repeats '(5 4 3 2 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(5 4 3 2 1 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(5 5 4 3 2 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(12)) - (12) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(1 1 1 1 1 1)) - (1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - }, - { - 'cases': [ - { - 'code': r""" - scm> (no-repeats (list 5 4 2)) - (5 4 2) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats (list 5 4 5 4 2 2)) - (5 4 2) - scm> (no-repeats (list 5 5 5 5 5)) - (5) - scm> (no-repeats ()) - () - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/pow.py b/hw/hw06/tests/pow.py deleted file mode 100644 index 809f97e34f..0000000000 --- a/hw/hw06/tests/pow.py +++ /dev/null @@ -1,52 +0,0 @@ -test = { - 'name': 'pow', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (pow 2 5) - 32 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 10 3) - 1000 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 3 3) - 27 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 1 100000000000000) ; make sure this doesn't run forever! - 1 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw06/tests/repeatedly-cube.py b/hw/hw06/tests/repeatedly-cube.py deleted file mode 100644 index 9f4dfd6cc2..0000000000 --- a/hw/hw06/tests/repeatedly-cube.py +++ /dev/null @@ -1,29 +0,0 @@ -test = { - 'name': 'repeatedly-cube', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (repeatedly-cube 3 1) - 1 - scm> (repeatedly-cube 2 2) - 512 - scm> (repeatedly-cube 3 2) - 134217728 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw07/assets/after.png b/hw/hw07/assets/after.png deleted file mode 100644 index cf8e95e510..0000000000 Binary files a/hw/hw07/assets/after.png and /dev/null differ diff --git a/hw/hw07/assets/before.png b/hw/hw07/assets/before.png deleted file mode 100644 index 6da4249e85..0000000000 Binary files a/hw/hw07/assets/before.png and /dev/null differ diff --git a/hw/hw07/hw07.ok b/hw/hw07/hw07.ok deleted file mode 100644 index 823c93915b..0000000000 --- a/hw/hw07/hw07.ok +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Homework 7", - "endpoint": "cal/cs61a/fa24/hw07", - "src": [ - "hw07.scm" - ], - "tests": { - "hw*.py": "doctest", - "tests/*.py": "ok_test" - }, - "default_tests": [ - "pow", - "repeatedly-cube", - "cadr-caddr" - ], - "protocols": [ - "restore", - "file_contents", - "unlock", - "grading", - "analytics", - "help", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw07/hw07.scm b/hw/hw07/hw07.scm deleted file mode 100644 index 8e64868415..0000000000 --- a/hw/hw07/hw07.scm +++ /dev/null @@ -1,15 +0,0 @@ -(define (square n) (* n n)) - -(define (pow base exp) 'YOUR-CODE-HERE) - -(define (repeatedly-cube n x) - (if (zero? n) - x - (let (_________________) - (* y y y)))) - -(define (cddr s) (cdr (cdr s))) - -(define (cadr s) 'YOUR-CODE-HERE) - -(define (caddr s) 'YOUR-CODE-HERE) diff --git a/hw/hw07/hw07.sql b/hw/hw07/hw07.sql deleted file mode 100644 index b48c0fc500..0000000000 --- a/hw/hw07/hw07.sql +++ /dev/null @@ -1,49 +0,0 @@ -CREATE TABLE parents AS - SELECT "abraham" AS parent, "barack" AS child UNION - SELECT "abraham" , "clinton" UNION - SELECT "delano" , "herbert" UNION - SELECT "fillmore" , "abraham" UNION - SELECT "fillmore" , "delano" UNION - SELECT "fillmore" , "grover" UNION - SELECT "eisenhower" , "fillmore"; - -CREATE TABLE dogs AS - SELECT "abraham" AS name, "long" AS fur, 26 AS height UNION - SELECT "barack" , "short" , 52 UNION - SELECT "clinton" , "long" , 47 UNION - SELECT "delano" , "long" , 46 UNION - SELECT "eisenhower" , "short" , 35 UNION - SELECT "fillmore" , "curly" , 32 UNION - SELECT "grover" , "short" , 28 UNION - SELECT "herbert" , "curly" , 31; - -CREATE TABLE sizes AS - SELECT "toy" AS size, 24 AS min, 28 AS max UNION - SELECT "mini" , 28 , 35 UNION - SELECT "medium" , 35 , 45 UNION - SELECT "standard" , 45 , 60; - - --- All dogs with parents ordered by decreasing height of their parent -CREATE TABLE by_parent_height AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- The size of each dog -CREATE TABLE size_of_dogs AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- Filling out this helper table is optional -CREATE TABLE siblings AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - --- Sentences about siblings that are the same size -CREATE TABLE sentences AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- Height range for each fur type where all of the heights differ by no more than 30% from the average height -CREATE TABLE low_variance AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - diff --git a/hw/hw07/hw07.zip b/hw/hw07/hw07.zip deleted file mode 100644 index dd1dd51215..0000000000 Binary files a/hw/hw07/hw07.zip and /dev/null differ diff --git a/hw/hw07/index.html b/hw/hw07/index.html deleted file mode 100644 index 8aca2df711..0000000000 --- a/hw/hw07/index.html +++ /dev/null @@ -1,489 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 7 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 7: Scheme - - - - - - -

-
- - -

Due by 11:59pm on Thursday, November 7

- - - - - -

Instructions

- -

Download hw07.zip. Inside the archive, you will find a file called -hw07.scm, along with a copy of the ok autograder.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - -

Readings: You might find the following references - useful:

- - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -

The 61A Scheme interpreter is included in each Scheme assignment. To start it, -type python3 scheme in a terminal. To load a Scheme file called f.scm, type python3 scheme -i f.scm. To exit the Scheme interpreter, type -(exit).

- -

Scheme Editor

- - -

All Scheme assignments include a web-based editor that makes it easy to run ok -tests and visualize environments. Type python3 editor in a terminal, and the -editor will open in a browser window (at http://127.0.0.1:31415/). Whatever -changes you make here will also save to the original file on your computer! -To stop running the editor and return to the command line, type Ctrl-C in the -terminal where you started the editor.

- -

The Run button loads the current assignment's .scm file and opens a Scheme -interpreter, allowing you to try evaluating different Scheme expressions.

- -

The Test button runs all ok tests for the assignment. Click View Case for a -failed test, then click Debug to step through its evaluation.

- - - - -

If you choose to use VS Code as your text editor (instead of the web-based editor), -install the vscode-scheme -extension so that parentheses are highlighted.

- -

Before:

- - - -

After:

- - - -

In addition, the 61a-bot (installation instructions) VS Code extension is available for Scheme homeworks. The bot is also integrated into ok.

- - -

Required Questions

- - -
- - -
- -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

-
- - -

Q1: Pow

- - -

Implement a procedure pow that raises a base to the power of a nonnegative integer exp. The number of recursive pow calls should grow logarithmically with respect to exp, rather than linearly. For example, (pow 2 32) should result in 5 recursive pow calls rather than 32 recursive pow calls.

- -

Hint:

- -
    -
  1. x2y = (xy)2
  2. -
  3. x2y+1 = x(xy)2
  4. -
- -

For example, 216 = (28)2 and 217 = 2 * (28)2.

- -

You may use the built-in predicates even? and odd?. Also, the square procedure is defined for you.

- -

Scheme doesn't have while or for statements, so use recursion to solve this problem.

- - - -
(define (square n) (* n n))
-
-(define (pow base exp)
-  'YOUR-CODE-HERE
-)
- - -
- -

Use Ok to test your code:

python3 ok -q pow
- -
- - - - -

Q2: Repeatedly Cube

- - -

Implement repeatedly-cube, which receives a number x and cubes it n times.

- -

Here are some examples of how repeatedly-cube should behave:

- -
scm> (repeatedly-cube 100 1) ; 1 cubed 100 times is still 1
-1
-scm> (repeatedly-cube 2 2) ; (2^3)^3
-512
-scm> (repeatedly-cube 3 2) ; ((2^3)^3)^3
-134217728
- - - -

For information on let, see the Scheme spec.

- - - -
(define (repeatedly-cube n x)
-    (if (zero? n)
-        x
-        (let
-            (_________________)
-            (* y y y))))
- - -
- -

Use Ok to test your code:

python3 ok -q repeatedly-cube
- -
- - - - -

Q3: Cadr

- - -

Define the procedure cadr, which returns the second element of a list. Also define caddr, which returns the third element of a list.

- - - -
(define (cddr s)
-  (cdr (cdr s)))
-
-(define (cadr s)
-  'YOUR-CODE-HERE
-)
-
-(define (caddr s)
-  'YOUR-CODE-HERE
-)
- - - -
- - - -

Use Ok to test your code:

python3 ok -q cadr-caddr
- -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw07/ok b/hw/hw07/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw07/ok and /dev/null differ diff --git a/hw/hw07/scheme b/hw/hw07/scheme deleted file mode 100644 index 2174145cff..0000000000 Binary files a/hw/hw07/scheme and /dev/null differ diff --git a/hw/hw07/sqlite_shell.py b/hw/hw07/sqlite_shell.py deleted file mode 100644 index cf1d3686fc..0000000000 --- a/hw/hw07/sqlite_shell.py +++ /dev/null @@ -1,681 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the MIT license - -# A simple SQLite shell that uses the built-in Python adapter. - -import codecs -import io -import os -import sys -import sqlite3 -import time -import warnings - -try: FileNotFoundError -except NameError: FileNotFoundError = OSError - -if str != bytes: buffer = bytes -if str != bytes: unicode = str - -try: import msvcrt -except ImportError: msvcrt = None - -CP_UTF8 = 65001 -pythonapi = None -if msvcrt: - import ctypes - (BOOL, DWORD, HANDLE, UINT) = (ctypes.c_long, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_uint) - GetConsoleCP = ctypes.WINFUNCTYPE(UINT)(('GetConsoleCP', ctypes.windll.kernel32)) - SetConsoleCP = ctypes.WINFUNCTYPE(BOOL, UINT)(('SetConsoleCP', ctypes.windll.kernel32)) - GetConsoleOutputCP = ctypes.WINFUNCTYPE(UINT)(('GetConsoleOutputCP', ctypes.windll.kernel32)) - SetConsoleOutputCP = ctypes.WINFUNCTYPE(BOOL, UINT)(('SetConsoleOutputCP', ctypes.windll.kernel32)) - GetConsoleMode = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.POINTER(DWORD), use_last_error=True)(('GetConsoleMode', ctypes.windll.kernel32)) - GetNumberOfConsoleInputEvents = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.POINTER(DWORD), use_last_error=True)(('GetNumberOfConsoleInputEvents', ctypes.windll.kernel32)) - ReadConsoleW = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.c_void_p, DWORD, ctypes.POINTER(DWORD), ctypes.c_void_p, use_last_error=True)(('ReadConsoleW', ctypes.windll.kernel32)) - WriteConsoleW = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.c_void_p, DWORD, ctypes.POINTER(DWORD), ctypes.c_void_p, use_last_error=True)(('WriteConsoleW', ctypes.windll.kernel32)) - class Py_buffer(ctypes.Structure): _fields_ = [('buf', ctypes.c_void_p), ('obj', ctypes.py_object), ('len', ctypes.c_ssize_t), ('itemsize', ctypes.c_ssize_t), ('readonly', ctypes.c_int), ('ndim', ctypes.c_int), ('format', ctypes.c_char_p), ('shape', ctypes.POINTER(ctypes.c_ssize_t)), ('strides', ctypes.POINTER(ctypes.c_ssize_t)), ('suboffsets', ctypes.POINTER(ctypes.c_ssize_t))] + ([('smalltable', ctypes.c_ssize_t * 2)] if sys.version_info[0] <= 2 else []) + [('internal', ctypes.c_void_p)] - try: from ctypes import pythonapi - except ImportError: pass -if pythonapi: - def getbuffer(b, writable): - arr = Py_buffer() - pythonapi.PyObject_GetBuffer(ctypes.py_object(b), ctypes.byref(arr), ctypes.c_int(writable)) - try: buf = (ctypes.c_ubyte * arr.len).from_address(arr.buf) - finally: pythonapi.PyBuffer_Release(ctypes.byref(arr)) - return buf - -ENCODING = 'utf-8' - -if sys.version_info[0] < 3: - class NotASurrogateError(Exception): pass - def surrogateescape_handler(exc): - # Source: https://github.com/PythonCharmers/python-future/blob/aef57391c0cd58bf840dff5e2bc2c8c0f5b0a1b4/src/future/utils/surrogateescape.py - mystring = exc.object[exc.start:exc.end] - try: - if isinstance(exc, UnicodeDecodeError): - decoded = [] - for ch in mystring: - if isinstance(ch, int): - code = ch - else: - code = ord(ch) - if 0x80 <= code <= 0xFF: - decoded.append(unichr(0xDC00 + code)) - elif code <= 0x7F: - decoded.append(unichr(code)) - else: - raise NotASurrogateError() - decoded = str().join(decoded) - elif isinstance(exc, UnicodeEncodeError): - decoded = [] - for ch in mystring: - code = ord(ch) - if not 0xD800 <= code <= 0xDCFF: - raise NotASurrogateError() - if 0xDC00 <= code <= 0xDC7F: - decoded.append(unichr(code - 0xDC00)) - elif code <= 0xDCFF: - decoded.append(unichr(code - 0xDC00)) - else: - raise NotASurrogateError() - decoded = str().join(decoded) - else: - raise exc - except NotASurrogateError: - raise exc - return (decoded, exc.end) - codecs.register_error('surrogateescape', surrogateescape_handler) - -def exception_encode(ex, codec): - if str == bytes: - reduced = ex.__reduce__() - ex = reduced[0](*tuple(map(lambda arg: codec.decode(arg)[0] if isinstance(arg, bytes) else arg, reduced[1]))) - return ex - -def sql_commands(read_line): - delims = ['"', "'", ';', '--'] - counter = 0 - in_string = None - j = i = 0 - prev_line = None - line = None - concat = [] - while True: - if line is None: - while True: # process preprocessor directives - counter += 1 - not_in_the_middle_of_any_input = not in_string and i == j and all(map(lambda chunk_: len(chunk_) == 0, concat)) - line = read_line(counter - 1, not_in_the_middle_of_any_input, prev_line) - empty_string = line[:0] if line is not None else line - prev_line = line - if not line: - break - if not_in_the_middle_of_any_input and line.startswith("."): - yield line - line = None - else: - break - if not line: - break - j = i = 0 - if j < len(line): - (j, delim) = min(map(lambda pair: pair if pair[0] >= 0 else (len(line), pair[1]), map(lambda d: (line.find(d, j), d), in_string or delims if in_string != '--' else "\n"))) - if i < j: concat.append(line[i:j]); i = j - if not in_string: - if j < len(line): - j += len(delim) - if delim == ';': - i = j - concat.append(line[j : j + len(delim)]) # ensure delimeter is the same type as the string (it may not be due to implicit conversion) - # Eat up any further spaces until a newline - while j < len(line): - delim = line[j:j+1] - if not delim.isspace(): break - j += 1 - if delim == "\n": break - if i < j: concat.append(line[i:j]); i = j - yield empty_string.join(concat) - del concat[:] - else: - in_string = delim - else: - if j < len(line): - ch = line[j:j+1] - assert ch == in_string or in_string == '--' - j += 1 - i = j - concat.append(ch) - in_string = None - else: - if i < j: concat.append(line[i:j]); i = j - line = None - -class WindowsConsoleIOMixin(object): - # Ctrl+C handling with ReadFile() is messed up on Windows starting on Windows 8... here's some background reading: - # https://stackoverflow.com/a/43260436 - # https://github.com/microsoft/terminal/issues/334 - # We use ReadConsole when we can, so it doesn't affect us, but it's good info to know regardless. - def __init__(self, fd): - assert isatty(fd), "file descriptor must refer to a console (note that on Windows, NUL satisfies isatty(), but is not a console)" - self.fd = fd - self.handle = msvcrt.get_osfhandle(fd) - def fileno(self): return self.fd - def isatty(self): return isatty(self.fd) - def seekable(self): return False - def readable(self): return GetNumberOfConsoleInputEvents(self.handle, ctypes.byref(DWORD(0))) != 0 - def writable(self): n = DWORD(0); return WriteConsoleW(self.handle, ctypes.c_void_p(), n, ctypes.byref(n), ctypes.c_void_p()) != 0 - def readwcharsinto(self, buf, n): - nr = DWORD(n) - old_error = ctypes.get_last_error() - ctypes.set_last_error(0) - success = ReadConsoleW(self.handle, buf, nr, ctypes.byref(nr), ctypes.c_void_p()) - error = ctypes.get_last_error() - ctypes.set_last_error(old_error) - if not success: raise ctypes.WinError(error) - ERROR_OPERATION_ABORTED = 995 - if nr.value == 0 and error == ERROR_OPERATION_ABORTED: - # Apparently this can trigger pending KeyboardInterrupts? - time.sleep(1.0 / (1 << 64)) - raise KeyboardInterrupt() # If Python doesn't raise it, we can - return nr.value - def writewchars(self, buf, n): - nw = DWORD(n) - if not WriteConsoleW(self.handle, buf, nw, ctypes.byref(nw), ctypes.c_void_p()): - raise ctypes.WinError() - return nw.value - -class WindowsConsoleRawIO(WindowsConsoleIOMixin, io.RawIOBase): - def readinto(self, b): - wordsize = ctypes.sizeof(ctypes.c_wchar) - return self.readwcharsinto(getbuffer(b, True), len(b) // wordsize) * wordsize - def write(self, b): - wordsize = ctypes.sizeof(ctypes.c_wchar) - return self.writewchars(getbuffer(b, False), len(b) // wordsize) * wordsize - -class WindowsConsoleTextIO(WindowsConsoleIOMixin, io.TextIOBase): - buf = None - buffered = unicode() - translate = True - def getbuf(self, ncodeunits): - buf = self.buf - if buf is None or len(buf) < ncodeunits: - self.buf = buf = ctypes.create_unicode_buffer(ncodeunits) - return buf - @staticmethod # Don't let classes override this... they can override the caller instead - def do_read(self, nchars, translate_newlines): - prenewline = os.linesep[:-1] - newline = os.linesep[-1:] - empty = os.linesep[:0] - if nchars is None or nchars < -1: nchars = -1 - ncodeunits = nchars if nchars >= 0 else io.DEFAULT_BUFFER_SIZE # Unit mismatch, but doesn't matter; we'll loop - buf = None - istart = 0 - while True: - iend = self.buffered.find(newline, istart, min(istart + nchars, len(self.buffered)) if nchars >= 0 else None) if newline is not None else nchars - if iend >= 0: iend += len(newline) if newline is not None else 0 - if 0 <= iend <= len(self.buffered): - break - if buf is None: buf = self.getbuf(ncodeunits) - istart = len(self.buffered) - chunk = buf[:self.readwcharsinto(buf, ncodeunits)] - if translate_newlines: chunk = chunk.replace(prenewline, empty) - if chunk.startswith('\x1A'): # EOF on Windows (Ctrl+Z) at the beginning of a line results in the entire rest of the buffer being discarded - iend = istart - break - # Python 2 and Python 3 behaviors differ on Windows... Python 2's sys.stdin.readline() just deletes the next character if it sees EOF in the middle of a string! I won't emulate that here. - self.buffered += chunk # We're relying on Python's concatenation optimization here... we don't do it ourselves, since we want self.buffered to be valid every iteration in case there is an exception raised - result = self.buffered[:iend] - self.buffered = self.buffered[iend:] - return result - def read(self, nchars=-1): return WindowsConsoleTextIO.do_read(self, nchars, None, self.translate) - def readline(self, nchars=-1): return WindowsConsoleTextIO.do_read(self, nchars, self.translate) - def write(self, text): buf = ctypes.create_unicode_buffer(text); return self.writewchars(buf, max(len(buf) - 1, 0)) - -def wrap_windows_console_io(stream, is_output): - fd = None - if stream is not None and sys.version_info[0] < 3 and msvcrt and (is_output or pythonapi) and isatty(stream): - try: fd = stream.fileno() - except io.UnsupportedOperation: pass - result = stream - if fd is not None: - f = GetConsoleOutputCP if is_output else GetConsoleCP - if not f or f() != CP_UTF8: - try: - if True or is_output: - result = WindowsConsoleTextIO(fd) - else: - result = io.TextIOWrapper((io.BufferedWriter if is_output else io.BufferedReader)(WindowsConsoleRawIO(fd)), 'utf-16-le', 'strict', line_buffering=True) - except IOError: pass - return result - -class NonOwningTextIOWrapper(io.TextIOWrapper): - def __init__(self, base_textiowrapper, **kwargs): - assert isinstance(base_textiowrapper, io.TextIOWrapper) - self.base = base_textiowrapper # must keep a reference to this alive so it doesn't get closed - super(NonOwningTextIOWrapper, self).__init__(base_textiowrapper.buffer, **kwargs) - def close(self): - super(NonOwningTextIOWrapper, self).flush() - -def wrap_unicode_stdio(stream, is_writer, encoding): # The underlying stream must NOT be used directly until the stream returned by this function is disposed of - if isinstance(stream, io.TextIOWrapper): - stream.flush() # Make sure nothing is left in the buffer before we re-wrap it - none = object() - kwargs = {} - for key in ['encoding', 'errors', 'newline', 'line_buffering', 'write_through']: - value = getattr(stream, 'newlines' if key == 'newline' else key, none) - if value is not none: - kwargs[key] = value - kwargs['encoding'] = encoding - result = NonOwningTextIOWrapper(stream, **kwargs) - elif 'PYTHONIOENCODING' not in os.environ and str == bytes and stream in (sys.stdin, sys.stdout, sys.stderr): - result = (codecs.getwriter if is_writer else codecs.getreader)(encoding)(stream) - else: - result = stream - return result - -class StringEscapeParser(object): - def __init__(self): - import re - self.pattern = re.compile("\"((?:[^\"\\n]+|\\\\.)*)(?:\"|$)|\'([^\'\\n]*)(?:\'|$)|(\\S+)") - self.escape_pattern = re.compile("\\\\(.)", re.DOTALL) - @staticmethod - def escape_replacement(m): - text = m.group(1) - if text == "\\": text = "\\" - elif text == "/": text = "\n" - elif text == "n": text = "\n" - elif text == "r": text = "\r" - elif text == "t": text = "\t" - elif text == "v": text = "\v" - elif text == "f": text = "\f" - elif text == "a": text = "\a" - elif text == "b": text = "\b" - return text - def __call__(self, s): - escape_pattern = self.escape_pattern - escape_replacement = self.escape_replacement - result = [] - for match in self.pattern.finditer(s): - [m1, m2, m3] = match.groups() - if m1 is not None: result.append(escape_pattern.sub(escape_replacement, m1)) - if m2 is not None: result.append(m2) - if m3 is not None: result.append(escape_pattern.sub(escape_replacement, m3)) - return result - -class Database(object): - def __init__(self, name, *args, **kwargs): - self.connection = sqlite3.connect(name, *args, **kwargs) - self.cursor = self.connection.cursor() - self.name = name # assign name only AFTER cursor is created - -def isatty(file_or_fd): - result = True - method = getattr(file_or_fd, 'isatty', None) if not isinstance(file_or_fd, int) else None # this check is just an optimization - if method is not None: - try: tty = method() - except io.UnsupportedOperation: tty = None - result = result and tty is not None and tty - method = getattr(file_or_fd, 'fileno', None) if not isinstance(file_or_fd, int) else None # this check is just an optimization - if method is not None: - try: fd = method() - except io.UnsupportedOperation: fd = None - result = result and fd is not None and os.isatty(fd) and (not msvcrt or GetConsoleMode(msvcrt.get_osfhandle(fd), ctypes.byref(DWORD(0))) != 0) - return result - -def can_call_input_for_stdio(stream): - return stream == sys.stdin and sys.version_info[0] >= 3 - -class StdIOProxy(object): - # Maybe useful later: codecs.StreamRecoder(bytesIO, codec.decode, codec.encode, codec.streamwriter, codec.streamreader, errors='surrogateescape') - def __init__(self, stdin, stdout, stderr, codec, allow_set_code_page): - self.codec = codec - streams = (stdin, stdout, stderr) - for stream in streams: - assert isinstance(stream, io.IOBase) or sys.version_info[0] < 3 and isinstance(stream, file) or hasattr(stream, 'mode'), "unable to determine stream type" - assert not isinstance(stream, io.RawIOBase), "RAW I/O APIs are different and not supported" - self.streaminfos = tuple(map(lambda stream: - ( - stream, - isinstance(stream, io.BufferedIOBase) or isinstance(stream, io.RawIOBase) or not isinstance(stream, io.TextIOBase) and 'b' in stream.mode, - isinstance(stream, io.TextIOBase) or not (isinstance(stream, io.BufferedIOBase) or isinstance(stream, io.RawIOBase)) and 'b' not in stream.mode, - allow_set_code_page - ), - streams)) - @property - def stdin(self): return self.streaminfos[0][0] - @property - def stdout(self): return self.streaminfos[1][0] - @property - def stderr(self): return self.streaminfos[2][0] - def _coerce(self, streaminfo, codec, arg): - stream = streaminfo[0] - can_binary = streaminfo[1] - can_text = streaminfo[2] - if not isinstance(arg, bytes) and not isinstance(arg, buffer) and not isinstance(arg, unicode): - arg = unicode(arg) - if isinstance(arg, bytes) or isinstance(arg, buffer): - if not can_binary: - arg = codec.decode(arg, 'surrogateescape')[0] - elif isinstance(arg, unicode): - if not can_text: - arg = codec.encode(unicode(arg), 'strict')[0] - return arg - @staticmethod - def _do_readline(stream, allow_set_code_page, *args): - new_code_page = CP_UTF8 - old_code_page = GetConsoleCP() if msvcrt and GetConsoleCP and isatty(stream) else None - if old_code_page == new_code_page: old_code_page = None # Don't change code page if it's already correct... - if old_code_page is not None: - if not SetConsoleCP(new_code_page): - old_code_page = None - try: - result = stream.readline(*args) - finally: - if old_code_page is not None: - SetConsoleCP(old_code_page) - return result - @staticmethod - def _do_write(stream, allow_set_code_page, *args): - new_code_page = CP_UTF8 - old_code_page = GetConsoleOutputCP() if msvcrt and GetConsoleOutputCP and isatty(stream) else None - if old_code_page == new_code_page: old_code_page = None # Don't change code page if it's already correct... - if old_code_page is not None: - if not SetConsoleOutputCP(new_code_page): - old_code_page = None - try: - result = stream.write(*args) - finally: - if old_code_page is not None: - SetConsoleCP(old_code_page) - return result - def _readln(self, streaminfo, codec, prompt): - stream = streaminfo[0] - can_binary = streaminfo[1] - allow_set_code_page = streaminfo[3] - if can_call_input_for_stdio(stream) and not can_binary: # input() can't work with binary data - result = self._coerce(streaminfo, codec, "") - try: - result = input(*((self._coerce(streaminfo, codec, prompt),) if prompt is not None else ())) - result += self._coerce(streaminfo, codec, "\n") - except EOFError: pass - else: - self.output(*((prompt,) if prompt is not None else ())) - self.error() - result = StdIOProxy._do_readline(stream, allow_set_code_page) - return result - def _writeln(self, streaminfo, codec, *args, **kwargs): - stream = streaminfo[0] - allow_set_code_page = streaminfo[3] - flush = kwargs.pop('flush', True) - kwargs.setdefault('end', '\n') - kwargs.setdefault('sep', ' ') - end = kwargs.get('end') - sep = kwargs.get('sep') - first = True - for arg in args: - if first: first = False - elif sep is not None: - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, sep)) - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, arg)) - if end is not None: - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, end)) - if flush: stream.flush() - def inputln(self, prompt=None): return self._readln(self.streaminfos[0], self.codec, prompt) - def output(self, *args, **kwargs): kwargs.setdefault('end', None); return self._writeln(self.streaminfos[1], self.codec, *args, **kwargs) - def outputln(self, *args, **kwargs): return self._writeln(self.streaminfos[1], self.codec, *args, **kwargs) - def error(self, *args, **kwargs): kwargs.setdefault('end', None); return self._writeln(self.streaminfos[2], self.codec, *args, **kwargs) - def errorln(self, *args, **kwargs): return self._writeln(self.streaminfos[2], self.codec, *args, **kwargs) - -class bytes_comparable_with_unicode(bytes): # For Python 2/3 compatibility, to allow implicit conversion between strings and bytes when it is safe. (Used for strings like literals which we know be safe.) - codec = codecs.lookup('ascii') # MUST be a safe encoding - @classmethod - def coerce(cls, other, for_output=False): - return cls.codec.encode(other)[0] if not isinstance(other, bytes) else bytes_comparable_with_unicode(other) if for_output else other - @classmethod - def translate_if_bytes(cls, value): - if value is not None and isinstance(value, bytes): value = cls(value) - return value - def __hash__(self): return super(bytes_comparable_with_unicode, self).__hash__() # To avoid warning - def __eq__(self, other): return super(bytes_comparable_with_unicode, self).__eq__(self.coerce(other)) - def __ne__(self, other): return super(bytes_comparable_with_unicode, self).__ne__(self.coerce(other)) - def __lt__(self, other): return super(bytes_comparable_with_unicode, self).__lt__(self.coerce(other)) - def __gt__(self, other): return super(bytes_comparable_with_unicode, self).__gt__(self.coerce(other)) - def __le__(self, other): return super(bytes_comparable_with_unicode, self).__le__(self.coerce(other)) - def __ge__(self, other): return super(bytes_comparable_with_unicode, self).__ge__(self.coerce(other)) - def __getitem__(self, index): return self.coerce(super(bytes_comparable_with_unicode, self).__getitem__(index), True) - def __add__(self, other): return self.coerce(super(bytes_comparable_with_unicode, self).__add__(self.coerce(other)), True) - def __iadd__(self, other): return self.coerce(super(bytes_comparable_with_unicode, self).__iadd__(self.coerce(other)), True) - def __radd__(self, other): return self.coerce(self.coerce(other).__add__(self), True) - def find(self, other, *args): return super(bytes_comparable_with_unicode, self).find(self.coerce(other), *args) - def join(self, others): return self.coerce(super(bytes_comparable_with_unicode, self).join(map(self.coerce, others)), True) - def startswith(self, other): return super(bytes_comparable_with_unicode, self).startswith(self.coerce(other)) - def __str__(self): return self.codec.decode(self)[0] - if str == bytes: - __unicode__ = __str__ - def __str__(self): raise NotImplementedError() - -def wrap_bytes_comparable_with_unicode_readline(readline): - def callback(*args): - line = readline(*args) - line = bytes_comparable_with_unicode.translate_if_bytes(line) - return line - return callback - -def main(program, *args, **kwargs): # **kwargs = dict(stdin=file, stdout=file, stderr=file); useful for callers who import this module - import argparse # slow import (compiles regexes etc.), so don't import it until needed - argparser = argparse.ArgumentParser( - prog=os.path.basename(program), - usage=None, - description=None, - epilog=None, - parents=[], - formatter_class=argparse.RawTextHelpFormatter) - argparser.add_argument('-version', '--version', action='store_true', help="show SQLite version") - argparser.add_argument('-batch', '--batch', action='store_true', help="force batch I/O") - argparser.add_argument('-init', '--init', metavar="FILE", help="read/process named file") - argparser.add_argument('filename', nargs='?', metavar="FILENAME", help="is the name of an SQLite database.\nA new database is created if the file does not previously exist.") - argparser.add_argument('sql', nargs='*', metavar="SQL", help="SQL commnds to execute after opening database") - argparser.add_argument('--readline', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to import readline if available (default: %(default)s)") - argparser.add_argument('--self-test', action='store_true', help="perform a basic self-test") - argparser.add_argument('--cross-test', action='store_true', help="perform a basic test against the official executable") - argparser.add_argument('--unicode-stdio', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to enable Unicode wrapper for standard I/O (default: %(default)s)") - argparser.add_argument('--console', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to auto-detect and use console window APIs (default: %(default)s)") - argparser.add_argument('--encoding', default=ENCODING, help="the default encoding to use (default: %(default)s)") - (stdin, stdout, stderr) = (kwargs.pop('stdin', sys.stdin), kwargs.pop('stdout', sys.stdout), kwargs.pop('stderr', sys.stderr)) - parsed_args = argparser.parse_args(args) - codec = codecs.lookup(parsed_args.encoding or argparser.get_default('encoding')) - if parsed_args.self_test: self_test(codec) - if parsed_args.cross_test: cross_test("sqlite3", codec) - parse_escaped_strings = StringEscapeParser() - if parsed_args.unicode_stdio == "true": - stdin = wrap_unicode_stdio(stdin, False, codec.name) - stdout = wrap_unicode_stdio(stdout, True, codec.name) - stderr = wrap_unicode_stdio(stderr, True, codec.name) - if parsed_args.console == "true": - stdin = wrap_windows_console_io(stdin, False) - stdout = wrap_windows_console_io(stdout, True) - stderr = wrap_windows_console_io(stderr, True) - allow_set_code_page = sys.version_info[0] < 3 and False # This is only necessary on Python 2 if we use the default I/O functions instead of bypassing to ReadConsole()/WriteConsole() - stdio = StdIOProxy(stdin, stdout, stderr, codec, allow_set_code_page) - db = None - no_args = len(args) == 0 - init_sql = parsed_args.sql - is_nonpipe_input = stdin.isatty() # NOT the same thing as TTY! (NUL and /dev/null are the difference) - init_show_prompt = not parsed_args.batch and is_nonpipe_input - if not parsed_args.batch and isatty(stdin) and (parsed_args.readline == "true" or __name__ == '__main__') and parsed_args.readline != "false": - try: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=DeprecationWarning) - import readline - except ImportError: pass - if parsed_args and parsed_args.version: - stdio.outputln(sqlite3.sqlite_version); - else: - filename = parsed_args.filename - if filename is None: filename = ":memory:" - db = Database(filename, isolation_level=None) - def exec_script(db, filename, ignore_io_errors): - try: - with io.open(filename, 'r', encoding=codec.name) as f: # Assume .sql files are text -- any binary data inside them should be X'' encoded, not embedded directly - for command in sql_commands(wrap_bytes_comparable_with_unicode_readline(lambda *args: (lambda s: (s) or None)(f.readline()))): - result = exec_command(db, command, False and ignore_io_errors) - if result is not None: - return result - except IOError as ex: - stdio.errorln(ex) - if not ignore_io_errors: return ex.errno - def raise_invalid_command_error(command): - if isinstance(command, bytes): command = codec.decode(command)[0] - if command.startswith("."): command = command[1:] - raise RuntimeError("Error: unknown command or invalid arguments: \"%s\". Enter \".help\" for help" % (command.rstrip().replace("\\", "\\\\").replace("\"", "\\\""),)) - def exec_command(db, command, ignore_io_errors): - results = None - query = None - query_parameters = {} - try: - if command.startswith("."): - args = list(parse_escaped_strings(command)) - if args[0] in (".quit", ".exit"): - return 0 - elif args[0] == ".help": - stdio.error(""" -.cd DIRECTORY Change the working directory to DIRECTORY -.dump Dump the database in an SQL text format -.exit Exit this program -.help Show this message -.open FILE Close existing database and reopen FILE -.print STRING... Print literal STRING -.quit Exit this program -.read FILENAME Execute SQL in FILENAME -.schema ?PATTERN? Show the CREATE statements matching PATTERN -.show Show the current values for various settings -.tables ?TABLE? List names of tables -""".lstrip()) - elif args[0] == ".cd": - if len(args) != 2: raise_invalid_command_error(command) - os.chdir(args[1]) - elif args[0] == ".dump": - if len(args) != 1: raise_invalid_command_error(command) - foreign_keys = db.cursor.execute("PRAGMA foreign_keys;").fetchone()[0] - if foreign_keys in (0, "0", "off", "OFF"): - stdio.outputln("PRAGMA foreign_keys=OFF;", flush=False) - for line in db.connection.iterdump(): - stdio.outputln(line, flush=False) - stdio.output() - elif args[0] == ".open": - if len(args) <= 1: raise_invalid_command_error(command) - filename = args[-1] - for option in args[+1:-1]: - raise ValueError("option %s not supported" % (repr(option),)) - try: db.__init__(filename) - except sqlite3.OperationalError as ex: - ex.args = ex.args[:0] + ("Error: unable to open database \"%s\": %s" % (filename, ex.args[0]),) + ex.args[1:] - raise - elif args[0] == ".print": - stdio.outputln(*args[1:]) - elif args[0] == ".read": - if len(args) != 2: raise_invalid_command_error(command) - exec_script(db, args[1], ignore_io_errors) - elif args[0] == ".schema": - if len(args) > 2: raise_invalid_command_error(command) - pattern = args[1] if len(args) > 1 else None - query_parameters['type'] = 'table' - if pattern is not None: - query_parameters['pattern'] = pattern - query = "SELECT sql || ';' FROM sqlite_master WHERE type = :type" + (" AND name LIKE :pattern" if pattern is not None else "") + ";" - elif args[0] == ".show": - if len(args) > 2: raise_invalid_command_error(command) - stdio.errorln(" filename:", db.name) - elif args[0] == ".tables": - if len(args) > 2: raise_invalid_command_error(command) - pattern = args[1] if len(args) > 1 else None - query_parameters['type'] = 'table' - if pattern is not None: - query_parameters['pattern'] = pattern - query = "SELECT name FROM sqlite_master WHERE type = :type" + (" AND name LIKE :pattern" if pattern is not None else "") + ";" - else: - raise_invalid_command_error(args[0]) - else: - query = command - if query is not None: - results = db.cursor.execute(query if isinstance(query, unicode) else codec.decode(query, 'surrogatereplace')[0], query_parameters) - except (RuntimeError, OSError, FileNotFoundError, sqlite3.OperationalError) as ex: - stdio.errorln(exception_encode(ex, codec)) - if results is not None: - for row in results: - stdio.outputln(*tuple(map(lambda item: item if item is not None else "", row)), sep="|", flush=False) - stdio.output() - if db: - if parsed_args and parsed_args.init: - if is_nonpipe_input: stdio.errorln("-- Loading resources from", parsed_args.init) - exec_script(db, parsed_args.init, False) - def read_stdin(index, not_in_the_middle_of_any_input, prev_line): - show_prompt = init_show_prompt - to_write = [] - if index < len(init_sql): - line = init_sql[index] - if not line.startswith(".") and not line.rstrip().endswith(";"): - line += ";" - elif index == len(init_sql) and len(init_sql) > 0: - line = None - else: - if show_prompt: - if not_in_the_middle_of_any_input: - show_prompt = False - if index == 0: - to_write.append("SQLite version %s (adapter version %s)\nEnter \".help\" for usage hints.\n" % (sqlite3.sqlite_version, sqlite3.version)) - if no_args: - to_write.append("Connected to a transient in-memory database.\nUse \".open FILENAME\" to reopen on a persistent database.\n") - if index > 0 and not prev_line: - to_write.append("\n") - to_write.append("%7s " % ("sqlite%s>" % ("",) if not_in_the_middle_of_any_input else "...>",)) - try: - line = stdio.inputln("".join(to_write)) - except KeyboardInterrupt: - line = "" - raise # just kidding, don't handle it for now... - return line - for command in sql_commands(wrap_bytes_comparable_with_unicode_readline(read_stdin)): - result = exec_command(db, command, True) - if result is not None: - return result - if init_show_prompt and len(init_sql) == 0: - stdio.outputln() - -def call_program(cmdline, input_text): - import subprocess - return subprocess.Popen(cmdline, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False).communicate(input_text) - -def test_query(): - hexcodec = codecs.lookup('hex_codec') - ascii = 'ascii' - data1 = b"\xD8\xA2" - data2 = b"\x01\x02\xFF\x01\xFF\xFE\xFD" - values = [data1, data2] - query_bytes = b'SELECT %s;' % (b", ".join(map(lambda b: b"X'%s'" % (hexcodec.encode(b)[0].upper(),), values)),) - expected_bytes = b"%s\n" % (b"|".join(values),) - return query_bytes, expected_bytes - -def cross_test(sqlite_cmdline, codec): - (query_bytes, expected_bytes) = test_query() - (official_output, official_error) = call_program(sqlite_cmdline, query_bytes) - # We can't use os.linesep here since binaries may belong to different platforms (Win32/MinGW vs. MSYS/Cygwin vs. WSL...) - official_output = official_output.replace(b"\r\n", b"\n") - official_error = official_error.replace(b"\r\n", b"\n") - if official_output != expected_bytes: - raise sqlite3.ProgrammingError("expected bytes are wrong: official %s != expected %s" % (repr(official_output), repr(expected_bytes))) - if official_error: - raise sqlite3.ProgrammingError("did not expect errors from official binary") - -def self_test(codec): - (query_bytes, expected_bytes) = test_query() - if not (lambda stdin, stdout, stderr: not main(sys.argv[0], stdin=stdin, stdout=stdout, stderr=stderr) and stdout.getvalue() == expected_bytes)(io.BytesIO(query_bytes), io.BytesIO(), io.BytesIO()): - raise sqlite3.ProgrammingError("byte I/O is broken") - if not (lambda stdin, stdout, stderr: not main(sys.argv[0], stdin=stdin, stdout=stdout, stderr=stderr) and stdout.getvalue() == codec.decode(expected_bytes, 'surrogateescape'))(io.StringIO(query_bytes.decode(ascii)), io.StringIO(), io.StringIO()): - raise sqlite3.ProgrammingError("string I/O is broken") - -if __name__ == '__main__': - import sys - exit_code = main(*sys.argv) - if exit_code not in (None, 0): raise SystemExit(exit_code) diff --git a/hw/hw07/tests/add-leaf.py b/hw/hw07/tests/add-leaf.py deleted file mode 100644 index 44c2b11d67..0000000000 --- a/hw/hw07/tests/add-leaf.py +++ /dev/null @@ -1,64 +0,0 @@ -test = { - 'name': 'add-leaf', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (define t (tree 1 nil)) - t - scm> (add-leaf t 10) - (1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (define t (tree 1 (list (tree 2 nil) (tree 3 nil)))) - t - scm> (add-leaf t 4) ; if you're getting (1 (2) (3) 4), make sure you're appending 2 *lists of trees* together! - (1 (2) (3) (4)) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (define t (tree 1 (list (tree 2 (list (tree 3 nil) (tree 4 nil))) (tree 3 nil)))) - t - scm> (add-leaf t 5) - (1 (2 (3) (4) (5)) (3) (5)) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (define t (tree 1 (list (tree 2 (list (tree 4 nil) (tree 5 nil))) (tree 3 (list (tree 6 nil) (tree 7 nil)))))) - t - scm> (add-leaf t 8) - (1 (2 (4) (5) (8)) (3 (6) (7) (8)) (8)) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - scm> (define (tree label branches) (cons label branches)) - scm> (define (label t) (car t)) - scm> (define (branches t) (cdr t)) - scm> (define (is-leaf t) (null? (branches t))) - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw07/tests/by_parent_height.py b/hw/hw07/tests/by_parent_height.py deleted file mode 100644 index ca1f57575b..0000000000 --- a/hw/hw07/tests/by_parent_height.py +++ /dev/null @@ -1,32 +0,0 @@ -test = { - 'name': 'by_parent_height', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM by_parent_height; - herbert - fillmore - abraham - delano - grover - barack - clinton - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': True, - 'scored': True, - 'setup': r""" - sqlite> .read hw07.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw07/tests/cadr-caddr.py b/hw/hw07/tests/cadr-caddr.py deleted file mode 100644 index 6d1ca8d194..0000000000 --- a/hw/hw07/tests/cadr-caddr.py +++ /dev/null @@ -1,43 +0,0 @@ -test = { - 'name': 'cadr-caddr', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (cddr '(1 2 3 4)) - (3 4) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (cadr '(1 2 3 4)) - 2 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (caddr '(1 2 3 4)) - 3 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw07/tests/low_variance.py b/hw/hw07/tests/low_variance.py deleted file mode 100644 index 933c64dfb1..0000000000 --- a/hw/hw07/tests/low_variance.py +++ /dev/null @@ -1,26 +0,0 @@ -test = { - 'name': 'low_variance', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM low_variance; - curly|1 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw07.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw07/tests/pow.py b/hw/hw07/tests/pow.py deleted file mode 100644 index 809f97e34f..0000000000 --- a/hw/hw07/tests/pow.py +++ /dev/null @@ -1,52 +0,0 @@ -test = { - 'name': 'pow', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (pow 2 5) - 32 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 10 3) - 1000 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 3 3) - 27 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (pow 1 100000000000000) ; make sure this doesn't run forever! - 1 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw07/tests/repeatedly-cube.py b/hw/hw07/tests/repeatedly-cube.py deleted file mode 100644 index 9f4dfd6cc2..0000000000 --- a/hw/hw07/tests/repeatedly-cube.py +++ /dev/null @@ -1,29 +0,0 @@ -test = { - 'name': 'repeatedly-cube', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (repeatedly-cube 3 1) - 1 - scm> (repeatedly-cube 2 2) - 512 - scm> (repeatedly-cube 3 2) - 134217728 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw07/tests/sentences.py b/hw/hw07/tests/sentences.py deleted file mode 100644 index ec53047c4d..0000000000 --- a/hw/hw07/tests/sentences.py +++ /dev/null @@ -1,27 +0,0 @@ -test = { - 'name': 'sentences', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM sentences; - The two siblings, barack and clinton, have the same size: standard - The two siblings, abraham and grover, have the same size: toy - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw07.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw07/tests/size_of_dogs.py b/hw/hw07/tests/size_of_dogs.py deleted file mode 100644 index 2d9e598028..0000000000 --- a/hw/hw07/tests/size_of_dogs.py +++ /dev/null @@ -1,30 +0,0 @@ -test = { - 'name': 'size_of_dogs', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT name FROM size_of_dogs WHERE size="toy" OR size="mini"; - abraham - eisenhower - fillmore - grover - herbert - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw07.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw08/assets/after.png b/hw/hw08/assets/after.png deleted file mode 100644 index cf8e95e510..0000000000 Binary files a/hw/hw08/assets/after.png and /dev/null differ diff --git a/hw/hw08/assets/before.png b/hw/hw08/assets/before.png deleted file mode 100644 index 6da4249e85..0000000000 Binary files a/hw/hw08/assets/before.png and /dev/null differ diff --git a/hw/hw08/hw08.ok b/hw/hw08/hw08.ok deleted file mode 100644 index 1c2530d20c..0000000000 --- a/hw/hw08/hw08.ok +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "Homework 8", - "endpoint": "cal/cs61a/fa24/hw08", - "src": [ - "hw08.scm" - ], - "tests": { - "hw*.py": "doctest", - "tests/*.py": "ok_test" - }, - "default_tests": [ - "ascending", - "filter", - "interleave", - "no_repeats" - ], - "protocols": [ - "restore", - "file_contents", - "grading", - "analytics", - "help", - "unlock", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw08/hw08.py b/hw/hw08/hw08.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/hw/hw08/hw08.scm b/hw/hw08/hw08.scm deleted file mode 100644 index b875bc325f..0000000000 --- a/hw/hw08/hw08.scm +++ /dev/null @@ -1,7 +0,0 @@ -(define (ascending? s) 'YOUR-CODE-HERE) - -(define (my-filter pred s) 'YOUR-CODE-HERE) - -(define (interleave lst1 lst2) 'YOUR-CODE-HERE) - -(define (no-repeats s) 'YOUR-CODE-HERE) diff --git a/hw/hw08/hw08.zip b/hw/hw08/hw08.zip deleted file mode 100644 index 1599714465..0000000000 Binary files a/hw/hw08/hw08.zip and /dev/null differ diff --git a/hw/hw08/index.html b/hw/hw08/index.html deleted file mode 100644 index 98c82bea94..0000000000 --- a/hw/hw08/index.html +++ /dev/null @@ -1,550 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 8 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 8: Scheme Lists - - - - - - -

-
- - -

Due by 11:59pm on Thursday, November 14

- - - - - -

Instructions

- -

Download hw08.zip. Inside the archive, you will find a file called -hw08.scm, along with a copy of the ok autograder.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - -

Readings: You might find the following references - useful:

- - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -

The 61A Scheme interpreter is included in each Scheme assignment. To start it, -type python3 scheme in a terminal. To load a Scheme file called f.scm, type python3 scheme -i f.scm. To exit the Scheme interpreter, type -(exit).

- -

Scheme Editor

- - -

All Scheme assignments include a web-based editor that makes it easy to run ok -tests and visualize environments. Type python3 editor in a terminal, and the -editor will open in a browser window (at http://127.0.0.1:31415/). Whatever -changes you make here will also save to the original file on your computer! -To stop running the editor and return to the command line, type Ctrl-C in the -terminal where you started the editor.

- -

The Run button loads the current assignment's .scm file and opens a Scheme -interpreter, allowing you to try evaluating different Scheme expressions.

- -

The Test button runs all ok tests for the assignment. Click View Case for a -failed test, then click Debug to step through its evaluation.

- - - - -

If you choose to use VS Code as your text editor (instead of the web-based editor), -install the vscode-scheme -extension so that parentheses are highlighted.

- -

Before:

- - - -

After:

- - - -

In addition, the 61a-bot (installation instructions) VS Code extension is available for Scheme homeworks. The bot is also integrated into ok.

- - -

Required Questions

- - - -

Required Questions

- - -
- - -
- -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

-
- - -

Q1: Ascending

- - -

Implement a procedure called ascending?, which takes a list of numbers s and -returns True if the numbers are in non-descending order, and False -otherwise.

- -

A list of numbers is non-descending if each element after the first is -greater than or equal to the previous element. For example...

- -
    -
  • (1 2 3 3 4) is non-descending.
  • -
  • (1 2 3 3 2) is not.
  • -
- -

Hint: The built-in null? procedure returns whether its argument is nil.

- - - -

Note: The question mark in ascending? is just part of the procedure name and has no special meaning in terms of Scheme syntax. It is a common practice in Scheme to name procedures with a question mark at the end if it returns a boolean value.

- -
(define (ascending? s)
-  'YOUR-CODE-HERE
-)
- - - - - -

Use Ok to unlock and test your code:

python3 ok -q ascending -u
-python3 ok -q ascending
- -
- - - -

Q2: My Filter

- - -

Write a procedure my-filter, which takes a predicate pred and a list s, and -returns a new list containing only elements of the list that satisfy the -predicate. The output should contain the elements in the same order that they -appeared in the original list.

- -

Note: Make sure that you are not just calling the built-in filter function in Scheme - we are asking you to re-implement this!

- - - -
(define (my-filter pred s)
-  'YOUR-CODE-HERE
-)
- - - -
- - -

Use Ok to unlock and test your code:

python3 ok -q filter -u
-python3 ok -q filter
- -
- - - -

Q3: Interleave

- - -

Implement the function interleave, which takes two lists lst1 and lst2 as -arguments. interleave should return a list that interleaves the elements -of the two lists. (In other words, the resulting list should contain elements -alternating between lst1 and lst2, starting at lst1).

- -

If one of the input lists to interleave is shorter than the other, then -interleave should alternate elements from both lists until one list has no -more elements, and then the remaining elements from the longer list should be -added to the end of the new list. If lst1 is empty, you may simply return -lst2 and vice versa.

- - - -

-    (define (interleave lst1 lst2)
-    'YOUR-CODE-HERE
-    )
- - - -
- -

Use Ok to unlock and test your code:

python3 ok -q interleave -u
-python3 ok -q interleave
- -
- - -

Q4: No Repeats

- - -

Implement no-repeats, which takes a list of numbers s. It returns a list -that has all of the unique elements of s in the order that they first appear, -but no repeats.

- -

For example, (no-repeats (list 5 4 5 4 2 2)) evaluates to (5 4 2).

- -

Hint: You may find it helpful to use filter with a lambda procedure to -filter out repeats. To test if two numbers a and b are not equal, use -(not (= a b)).

- - - -
(define (no-repeats s)
-  'YOUR-CODE-HERE
-)
- - - - -
- -

Use Ok to test your code:

python3 ok -q no_repeats
- -
- - -

Submit Assignment

- - -

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

- - -

Exam Practice

- -

The following are some Scheme List exam problems from previous semesters that you may find useful as additional exam practice.

- -
    -
  1. Fall 2022 Final, Question 8: A Parentheses Scheme
  2. -
  3. Spring 2022 Final, Question 11: Beadazzled, The Scheme-quel
  4. -
  5. Fall 2021 Final, Question 4: Spice
  6. -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw08/ok b/hw/hw08/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw08/ok and /dev/null differ diff --git a/hw/hw08/scheme b/hw/hw08/scheme deleted file mode 100644 index 2174145cff..0000000000 Binary files a/hw/hw08/scheme and /dev/null differ diff --git a/hw/hw08/tests/ascending.py b/hw/hw08/tests/ascending.py deleted file mode 100644 index 42bf14ad65..0000000000 --- a/hw/hw08/tests/ascending.py +++ /dev/null @@ -1,66 +0,0 @@ -test = { - 'name': 'ascending?', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (ascending? '(1 2 3 4 5)) ; #t or #f - 545654f52801dba9cbbe0347d265df09 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(1 5 2 4 3)) ; #t or #f - 8cd49ce066289d3b150d7b6108dda61e - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(2 2)) ; #t or #f - 545654f52801dba9cbbe0347d265df09 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '(1 2 2 4 3)) ; #t or #f - 8cd49ce066289d3b150d7b6108dda61e - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (ascending? '()) ; #t or #f - 545654f52801dba9cbbe0347d265df09 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw08/tests/filter.py b/hw/hw08/tests/filter.py deleted file mode 100644 index 21ec72568f..0000000000 --- a/hw/hw08/tests/filter.py +++ /dev/null @@ -1,87 +0,0 @@ -test = { - 'name': 'my-filter', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (my-filter even? '(1 2 3 4)) - 2e37dffeac959437a227984e265073d8 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? '(1 3 5)) - 4937c69c365e96f0a6c22b735cfbca8c - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? '(2 4 6 1)) - 4fbb2195709ce6677a192b31dd920a41 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter even? '(3)) - 7e44d32911eb855f7a970358ab156a57 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (my-filter odd? nil) - 7e44d32911eb855f7a970358ab156a57 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - }, - { - 'cases': [ - { - 'code': r""" - scm> (my-filter even? '(1 2 3 4)) ; checks you dont use builtin filter - 2e37dffeac959437a227984e265073d8 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (define filter nil) - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw08/tests/interleave.py b/hw/hw08/tests/interleave.py deleted file mode 100644 index 3d6d65fb16..0000000000 --- a/hw/hw08/tests/interleave.py +++ /dev/null @@ -1,92 +0,0 @@ -test = { - 'name': 'interleave', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (interleave (list 1 3 5) (list 2 4)) - 412c86fdd30eb01c0f6c1406c57c1f4f - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (interleave (list 2 4) (list 1 3 5)) - 60907ae99fb65ba6572aef8d20f2d98f - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (interleave (list 1 2) (list 1 2)) - 97e297aeda7ca131b3ce5d660712ba37 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (interleave '(1 2 3 4 5 6) '(7 8)) - 68dcbeaae19114527ba0f3fa3158aa68 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - }, - { - 'cases': [ - { - 'code': r""" - scm> (interleave (list 1 3 5) (list 2 4 6)) - 79344590f746836ebf255704a9ec6a23 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - }, - { - 'code': r""" - scm> (interleave (list 1 3 5) nil) - 4937c69c365e96f0a6c22b735cfbca8c - # locked - scm> (interleave nil (list 1 3 5)) - 4937c69c365e96f0a6c22b735cfbca8c - # locked - scm> (interleave nil nil) - 7e44d32911eb855f7a970358ab156a57 - # locked - """, - 'hidden': False, - 'locked': True, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw08/tests/no_repeats.py b/hw/hw08/tests/no_repeats.py deleted file mode 100644 index 908613a788..0000000000 --- a/hw/hw08/tests/no_repeats.py +++ /dev/null @@ -1,93 +0,0 @@ -test = { - 'name': 'no-repeats', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (no-repeats '(5 4 3 2 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(5 4 3 2 1 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(5 5 4 3 2 1)) - (5 4 3 2 1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(12)) - (12) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats '(1 1 1 1 1 1)) - (1) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - }, - { - 'cases': [ - { - 'code': r""" - scm> (no-repeats (list 5 4 2)) - (5 4 2) - """, - 'hidden': False, - 'locked': False, - 'multiline': False - }, - { - 'code': r""" - scm> (no-repeats (list 5 4 5 4 2 2)) - (5 4 2) - scm> (no-repeats (list 5 5 5 5 5)) - (5) - scm> (no-repeats ()) - () - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw09/assets/after.png b/hw/hw09/assets/after.png deleted file mode 100644 index cf8e95e510..0000000000 Binary files a/hw/hw09/assets/after.png and /dev/null differ diff --git a/hw/hw09/assets/before.png b/hw/hw09/assets/before.png deleted file mode 100644 index 6da4249e85..0000000000 Binary files a/hw/hw09/assets/before.png and /dev/null differ diff --git a/hw/hw09/hw09.ok b/hw/hw09/hw09.ok deleted file mode 100644 index 80a70086cb..0000000000 --- a/hw/hw09/hw09.ok +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Homework 9", - "endpoint": "cal/cs61a/fa24/hw09", - "src": [ - "hw09.scm" - ], - "tests": { - "hw*.py": "doctest", - "tests/*.py": "ok_test" - }, - "default_tests": [ - "curry-cook", - "curry-consume", - "switch-to-cond" - ], - "protocols": [ - "restore", - "file_contents", - "grading", - "analytics", - "help", - "unlock", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw09/hw09.scm b/hw/hw09/hw09.scm deleted file mode 100644 index 99e5a45f6b..0000000000 --- a/hw/hw09/hw09.scm +++ /dev/null @@ -1,13 +0,0 @@ -(define (curry-cook formals body) 'YOUR-CODE-HERE) - -(define (curry-consume curry args) - 'YOUR-CODE-HERE) - -(define-macro (switch expr options) - (switch-to-cond (list 'switch expr options))) - -(define (switch-to-cond switch-expr) - (cons _________ - (map (lambda (option) - (cons _______________ (cdr option))) - (car (cdr (cdr switch-expr)))))) diff --git a/hw/hw09/hw09.zip b/hw/hw09/hw09.zip deleted file mode 100644 index 2afadca8d5..0000000000 Binary files a/hw/hw09/hw09.zip and /dev/null differ diff --git a/hw/hw09/index.html b/hw/hw09/index.html deleted file mode 100644 index 925b1fad08..0000000000 --- a/hw/hw09/index.html +++ /dev/null @@ -1,551 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 9 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 9: Programs as Data, Macros - - - - - - -

-
- - -

Due by 11:59pm on Thursday, November 21

- - - - - -

Instructions

- -

Download hw09.zip. Inside the archive, you will find a file called -hw09.scm, along with a copy of the ok autograder.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - -

Readings: You might find the following references - useful:

- - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -

The 61A Scheme interpreter is included in each Scheme assignment. To start it, -type python3 scheme in a terminal. To load a Scheme file called f.scm, type python3 scheme -i f.scm. To exit the Scheme interpreter, type -(exit).

- -

Scheme Editor

- - -

All Scheme assignments include a web-based editor that makes it easy to run ok -tests and visualize environments. Type python3 editor in a terminal, and the -editor will open in a browser window (at http://127.0.0.1:31415/). Whatever -changes you make here will also save to the original file on your computer! -To stop running the editor and return to the command line, type Ctrl-C in the -terminal where you started the editor.

- -

The Run button loads the current assignment's .scm file and opens a Scheme -interpreter, allowing you to try evaluating different Scheme expressions.

- -

The Test button runs all ok tests for the assignment. Click View Case for a -failed test, then click Debug to step through its evaluation.

- - - - -

If you choose to use VS Code as your text editor (instead of the web-based editor), -install the vscode-scheme -extension so that parentheses are highlighted.

- -

Before:

- - - -

After:

- - - -

In addition, the 61a-bot (installation instructions) VS Code extension is available for Scheme homeworks. The bot is also integrated into ok.

- - -

Required Questions

- - -
- - -
- - -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

- -
- - -

Programs as Data: Chef Curry

- - -

Recall that currying transforms a multiple argument function into a series of higher-order, one argument functions. In the next set of questions, you will be creating functions that can automatically curry a function of any length using the notion that programs are data!

- - -

Q1: Cooking Curry

- - -

Implement the function curry-cook, which takes in a Scheme list formals and a quoted expression body. curry-cook should generate a program as a list which is a curried version of a lambda function. The outputted program should be a curried version of a lambda function with formal arguments equal to formals, and a function body equal to body. You may assume that all functions passed in will have more than 0 formals; otherwise, it would not be curry-able!

- -

For example, if you wanted to curry the function (lambda (x y) (+ x y)), you would set formals equal to '(x y), the body equal to '(+ x y), and make a call to curry-cook: (curry-cook '(x y) '(+ x y)).

- -
scm> (curry-cook '(a) 'a)
-(lambda (a) a)
-scm> (curry-cook '(x y) '(+ x y))
-(lambda (x) (lambda (y) (+ x y)))
- - - - - -
(define (curry-cook formals body)
-    'YOUR-CODE-HERE
-)
- - -
- -

Use Ok to test your code:

python3 ok -q curry-cook
- -
- - -

Q2: Consuming Curry

- - - - -

Implement the function curry-consume, which takes in a curried lambda function curry and applies the function to a list of arguments args. You may make the following assumptions:

- -
    -
  1. If curry is an n-curried function, then there will be at most n arguments in args.
  2. -
  3. If there are 0 arguments (args is an empty list), then you may assume that curry has been fully applied with relevant arguments; in this case, curry now contains a value representing the output of the lambda function. Return it.
  4. -
- -

Note that there can be fewer args than formals for the corresponding lambda function curry! In the case that there are fewer arguments, curry-consume should return a curried lambda function, which is the result of partially applying curry up to the number of args provdied. See the doctests below for a few examples.

- -
scm> (define three-curry (lambda (x) (lambda (y) (lambda (z) (+ x (* y z)))) ))
-three-curry
-scm> (define eat-two (curry-consume three-curry '(1 2))) ; pass in only two arguments, return should be a one-arg lambda function!
-eat-two
-scm> eat-two
-(lambda (z) (+ x (* y z)))
-scm> (eat-two 3) ; pass in the last argument; 1 + (2 * 3)
-7
-scm> (curry-consume three-curry '(1 2 3)) ; all three arguments at once
-7
- - - - - -
(define (curry-consume curry args)
-    'YOUR-CODE-HERE
-)
- - -
- -

Use Ok to test your code:

python3 ok -q curry-consume
- -
- - -

Macros

- - -

Q3: Switch to Cond

- - -

switch is a macro that takes in an expression expr and a list of pairs, options, where the first element of each pair is some value and the second element is a single expression. switch evaluates the expression contained in the list of options that corresponds to the value that expr evaluates to.

- -
scm> (switch (+ 1 1) ((1 (print 'a))
-                      (2 (print 'b)) ; (print 'b) is evaluated because (+ 1 1) evaluates to 2
-                      (3 (print 'c))))
-b
- - - -

switch uses another procedure called switch-to-cond in its implementation:

- -
scm> (define-macro (switch expr options)
-                   (switch-to-cond (list 'switch expr options))
-     )
- - -
- -

Your task is to define switch-to-cond, which is a procedure (not a macro) that takes a quoted switch expression and converts it into a cond expression with the same behavior. An example is shown below.

- -
scm> (switch-to-cond `(switch (+ 1 1) ((1 2) (2 4) (3 6))))
-(cond ((equal? (+ 1 1) 1) 2) ((equal? (+ 1 1) 2) 4) ((equal? (+ 1 1) 3) 6))
- - - - - -
(define-macro (switch expr options) (switch-to-cond (list 'switch expr options)))
-
-(define (switch-to-cond switch-expr)
-  (cons _________
-    (map
-	  (lambda (option) (cons _______________ (cdr option)))
-	  (car (cdr (cdr switch-expr))))))
- - -
- -

Use Ok to test your code:

python3 ok -q switch-to-cond
- -
- - -

Check Your Score Locally

- -

You can locally check your score on each question of this assignment by running

- -
python3 ok --score
- -

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

- -

Submit Assignment

- - -

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

- - -

Exam Practice

- - -

Homework assignments will also contain prior exam questions for you to try. -These questions have no submission component; feel free to attempt them if you'd like some practice!

- -

Macros

- -
    -
  1. Fall 2019 Final Q9: Macro Lens
  2. -
  3. Summer 2019 Final Q10c: Slice
  4. -
  5. Spring 2019 Final Q8: Macros
  6. -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw09/ok b/hw/hw09/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw09/ok and /dev/null differ diff --git a/hw/hw09/scheme b/hw/hw09/scheme deleted file mode 100644 index 2174145cff..0000000000 Binary files a/hw/hw09/scheme and /dev/null differ diff --git a/hw/hw09/tests/curry-consume.py b/hw/hw09/tests/curry-consume.py deleted file mode 100644 index bac2bd1968..0000000000 --- a/hw/hw09/tests/curry-consume.py +++ /dev/null @@ -1,37 +0,0 @@ -test = { - 'name': 'curry-consume', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (define three-curry (curry-cook '(x y z) '(+ x (* y z)))) - three-curry - scm> three-curry - (lambda (x) (lambda (y) (lambda (z) (+ x (* y z))))) - scm> (define three-curry-fn (eval three-curry)) ; three-curry-fn is a lambda function derived from the program - three-curry-fn - scm> (define eat-two (curry-consume three-curry-fn '(1 2))) ; pass in only two arguments, return should be a one-arg lambda function! - eat-two - scm> eat-two - (lambda (z) (+ x (* y z))) - scm> (eat-two 3) ; pass in the last argument; 1 + (2 * 3) - 7 - scm> (curry-consume three-curry-fn '(1 2 3)) ; all three arguments at once! - 7 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw09/tests/curry-cook.py b/hw/hw09/tests/curry-cook.py deleted file mode 100644 index 4fac3a8048..0000000000 --- a/hw/hw09/tests/curry-cook.py +++ /dev/null @@ -1,33 +0,0 @@ -test = { - 'name': 'curry-cook', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (curry-cook '(a) 'a) - (lambda (a) a) - scm> (curry-cook '(x y) '(+ x y)) - (lambda (x) (lambda (y) (+ x y))) - scm> (define adder (curry-cook '(x y) '(+ x y))) - adder - scm> (eval adder) - (lambda (x) (lambda (y) (+ x y))) - scm> (((eval adder) 2) 3) - 5 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw09/tests/switch-to-cond.py b/hw/hw09/tests/switch-to-cond.py deleted file mode 100644 index 4825bdd178..0000000000 --- a/hw/hw09/tests/switch-to-cond.py +++ /dev/null @@ -1,41 +0,0 @@ -test = { - 'name': 'switch-to-cond', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - scm> (switch-to-cond `(switch (+ 1 1) ((1 2) - .... (2 4) - .... (3 6)))) - (cond ((equal? (+ 1 1) 1) 2) ((equal? (+ 1 1) 2) 4) ((equal? (+ 1 1) 3) 6)) - scm> (switch 1 ((1 (print 'a)) - .... (2 (print 'b)) - .... (3 (print 'c)))) - a - scm> (switch (+ 1 1) ((1 (print 'a)) - .... (2 (print 'b)) - .... (3 (print 'c)))) - b - scm> (define x 'b) - x - scm> (switch x (('a (print 1)) - .... ('b (print 2)) - .... ('c (print 3)))) - 2 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'scored': True, - 'setup': r""" - scm> (load-all ".") - """, - 'teardown': '', - 'type': 'scheme' - } - ] -} diff --git a/hw/hw10/data.sql b/hw/hw10/data.sql deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/hw/hw10/hw10.ok b/hw/hw10/hw10.ok deleted file mode 100644 index 8959ce5fff..0000000000 --- a/hw/hw10/hw10.ok +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "Homework 10", - "endpoint": "cal/cs61a/fa24/hw10", - "src": [ - "hw10.sql", - "hw10.py" - ], - "tests": { - "hw*.py": "doctest", - "tests/*.py": "ok_test" - }, - "default_tests": [ - "by_parent_height", - "size_of_dogs", - "sentences", - "low_variance" - ], - "protocols": [ - "restore", - "file_contents", - "unlock", - "grading", - "analytics", - "help", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw10/hw10.sql b/hw/hw10/hw10.sql deleted file mode 100644 index b48c0fc500..0000000000 --- a/hw/hw10/hw10.sql +++ /dev/null @@ -1,49 +0,0 @@ -CREATE TABLE parents AS - SELECT "abraham" AS parent, "barack" AS child UNION - SELECT "abraham" , "clinton" UNION - SELECT "delano" , "herbert" UNION - SELECT "fillmore" , "abraham" UNION - SELECT "fillmore" , "delano" UNION - SELECT "fillmore" , "grover" UNION - SELECT "eisenhower" , "fillmore"; - -CREATE TABLE dogs AS - SELECT "abraham" AS name, "long" AS fur, 26 AS height UNION - SELECT "barack" , "short" , 52 UNION - SELECT "clinton" , "long" , 47 UNION - SELECT "delano" , "long" , 46 UNION - SELECT "eisenhower" , "short" , 35 UNION - SELECT "fillmore" , "curly" , 32 UNION - SELECT "grover" , "short" , 28 UNION - SELECT "herbert" , "curly" , 31; - -CREATE TABLE sizes AS - SELECT "toy" AS size, 24 AS min, 28 AS max UNION - SELECT "mini" , 28 , 35 UNION - SELECT "medium" , 35 , 45 UNION - SELECT "standard" , 45 , 60; - - --- All dogs with parents ordered by decreasing height of their parent -CREATE TABLE by_parent_height AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- The size of each dog -CREATE TABLE size_of_dogs AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- Filling out this helper table is optional -CREATE TABLE siblings AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - --- Sentences about siblings that are the same size -CREATE TABLE sentences AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - - --- Height range for each fur type where all of the heights differ by no more than 30% from the average height -CREATE TABLE low_variance AS - SELECT "REPLACE THIS LINE WITH YOUR SOLUTION"; - diff --git a/hw/hw10/hw10.zip b/hw/hw10/hw10.zip deleted file mode 100644 index 09f606cb0b..0000000000 Binary files a/hw/hw10/hw10.zip and /dev/null differ diff --git a/hw/hw10/index.html b/hw/hw10/index.html deleted file mode 100644 index 09f1bb41f6..0000000000 --- a/hw/hw10/index.html +++ /dev/null @@ -1,590 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 10 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 10: SQL - - - - - - -

-
- - -

Due by 11:59pm on Wednesday, December 4

- - - - - -

Instructions

- -

Download hw10.zip.

- -

Submission: When you are done, submit the assignment by uploading all code files you've edited to Gradescope. You may submit more than once before the deadline; only the -final submission will be scored. Check that you have successfully submitted -your code on Gradescope. See Lab 0 for more instructions on -submitting assignments.

- -

Using Ok: If you have any questions about using Ok, please -refer to this guide. - - - -

Grading: Homework is graded based on -correctness. Each incorrect problem will decrease the total score by one point. -This homework is out of 2 points. - - - - - -
- -

To check your progress, you can run sqlite3 directly by running:

- -
python3 sqlite_shell.py --init hw10.sql
- -

You should also check your work using ok:

- -
python3 ok
- - -

Required Questions

- - -
- -
- - -
- - -

Getting Started Videos

- - -

These videos may provide some helpful direction for tackling the coding -problems on this assignment.

- -

To see these videos, you should be logged into your berkeley.edu email.

- - -

YouTube link

- -
- - -

SQL

- - - -

Dog Data

- - -

In each question below, you will define a new table based on the following -tables.

- -
CREATE TABLE parents AS
-  SELECT "abraham" AS parent, "barack" AS child UNION
-  SELECT "abraham"          , "clinton"         UNION
-  SELECT "delano"           , "herbert"         UNION
-  SELECT "fillmore"         , "abraham"         UNION
-  SELECT "fillmore"         , "delano"          UNION
-  SELECT "fillmore"         , "grover"          UNION
-  SELECT "eisenhower"       , "fillmore";
-
-CREATE TABLE dogs AS
-  SELECT "abraham" AS name, "long" AS fur, 26 AS height UNION
-  SELECT "barack"         , "short"      , 52           UNION
-  SELECT "clinton"        , "long"       , 47           UNION
-  SELECT "delano"         , "long"       , 46           UNION
-  SELECT "eisenhower"     , "short"      , 35           UNION
-  SELECT "fillmore"       , "curly"      , 32           UNION
-  SELECT "grover"         , "short"      , 28           UNION
-  SELECT "herbert"        , "curly"      , 31;
-
-CREATE TABLE sizes AS
-  SELECT "toy" AS size, 24 AS min, 28 AS max UNION
-  SELECT "mini"       , 28       , 35        UNION
-  SELECT "medium"     , 35       , 45        UNION
-  SELECT "standard"   , 45       , 60;
- -

Your tables should still perform correctly even if the values in these tables -change. For example, if you are asked to list all dogs with a name that starts -with h, you should write:

- -
SELECT name FROM dogs WHERE "h" <= name AND name < "i";
- -

Instead of assuming that the dogs table has only the data above and writing

- -
SELECT "herbert";
- -

The former query would still be correct if the name grover were changed to -hoover or a row was added with the name harry.

- - -

Q1: By Parent Height

- -

Create a table by_parent_height that has a column of the names of all dogs that have -a parent, ordered by the height of the parent dog from tallest parent to shortest -parent.

- -
-- All dogs with parents ordered by decreasing height of their parent
-CREATE TABLE by_parent_height AS
-  SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";
-
- -

For example, fillmore has a parent eisenhower with height 35, and so -should appear before grover who has a parent fillmore with height 32. -The names of dogs with parents of the same height should appear together in any -order. For example, barack and clinton should both appear at the end, but -either one can come before the other.

- -
sqlite> SELECT * FROM by_parent_height;
-herbert
-fillmore
-abraham
-delano
-grover
-barack
-clinton
- -

Use Ok to test your code:

python3 ok -q by_parent_height
- -
- - - - - -

Q2: Size of Dogs

- -

The Fédération Cynologique Internationale classifies a standard poodle as over -45 cm and up to 60 cm. The sizes table describes this and other such -classifications, where a dog must be over the min and less than or equal to -the max in height to qualify as size.

- -

Create a size_of_dogs table with two columns, one for each dog's name and -another for its size.

- -
-- The size of each dog
-CREATE TABLE size_of_dogs AS
-  SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";
-
- -

The output should look like the following:

- -
sqlite> SELECT * FROM size_of_dogs;
-abraham|toy
-barack|standard
-clinton|standard
-delano|standard
-eisenhower|mini
-fillmore|mini
-grover|toy
-herbert|mini
- -

Use Ok to test your code:

python3 ok -q size_of_dogs
- -
- - - - - - -

Q3: Sentences

- -

There are two pairs of siblings that have the same size. Create a table that -contains a row with a string for each of these pairs. Each string should be a -sentence describing the siblings by their size.

- -
-- Filling out this helper table is optional
-CREATE TABLE siblings AS
-  SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";
-
--- Sentences about siblings that are the same size
-CREATE TABLE sentences AS
-  SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";
-
- -

Each sibling pair should appear only once in the output, and siblings should be -listed in alphabetical order (e.g. "barack and clinton..." instead of -"clinton and barack..."), as follows:

- -
sqlite> SELECT * FROM sentences;
-The two siblings, barack and clinton, have the same size: standard
-The two siblings, abraham and grover, have the same size: toy
- -

Hint: First, create a helper table containing each pair of siblings. This -will make comparing the sizes of siblings when constructing the main table -easier.

- -

Hint: If you join a table with itself, use AS within the FROM clause to -give each table an alias.

- -

Hint: In order to concatenate two strings into one, use the || operator.

- - - -

Use Ok to test your code:

python3 ok -q sentences
- -
- - - - -

Q4: Low Variance

- - -

We want to create a table that contains the height range (difference between maximum and minimum height) of all dogs that share a fur type. However, we'll only -consider fur types where each dog with that fur type is within 30% of the average height of all dogs with that fur type.

- -

For example, if the average height for short-haired dogs is 10, then in order to be included in our -output, all dogs with short hair must have a height of at most 13 and at least 7.

- -

To achieve this, we can use MIN, MAX, and AVG. -For this problem, we'll want to find the average height and make sure that:

- -
    -
  • There are no heights smaller than 0.7 of the average.
  • -
  • There are no heights greater than 1.3 of the average.
  • -
- -

Your output should first include the fur type and then the height range for the fur types that meet -this criteria.

- -
-- Height range for each fur type where all of the heights differ by no more than 30% from the average height
-CREATE TABLE low_variance AS
-  SELECT "REPLACE THIS LINE WITH YOUR SOLUTION";
-
--- Example:
-SELECT * FROM low_variance;
--- Expected output:
--- curly|1
- -

Explanation: The average height of long-haired dogs is 39.7, so the low variance criterion requires the height of each long-haired dog to be between 27.8 and 51.6. However, abraham is a long-haired dog with height 26, which is outside this range. For short-haired dogs, barack falls outside the valid range (check!). Thus, neither short nor long haired dogs are included in the output. There are two curly haired dogs: fillmore with height 32 and herbert with height 31. This gives a height range of 1.

- -

Use Ok to test your code:

python3 ok -q low_variance
- -
- - -

Submit Assignment

- - -

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

- -

Make sure to submit hw10.sql to the autograder!

- - -

Exam Practice

- - -

The following are some SQL exam problems from previous semesters that you may find useful as additional exam practice.

- -
    -
  1. Fall 2019 Final, Question 10: Big Game
  2. -
  3. Summer 2019 Final, Question 8: The Big SQL
  4. -
  5. Fall 2018 Final, Question 7: SQL of Course
  6. -
- - - - -
- - -
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw10/ok b/hw/hw10/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw10/ok and /dev/null differ diff --git a/hw/hw10/sqlite_shell.py b/hw/hw10/sqlite_shell.py deleted file mode 100644 index cf1d3686fc..0000000000 --- a/hw/hw10/sqlite_shell.py +++ /dev/null @@ -1,681 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the MIT license - -# A simple SQLite shell that uses the built-in Python adapter. - -import codecs -import io -import os -import sys -import sqlite3 -import time -import warnings - -try: FileNotFoundError -except NameError: FileNotFoundError = OSError - -if str != bytes: buffer = bytes -if str != bytes: unicode = str - -try: import msvcrt -except ImportError: msvcrt = None - -CP_UTF8 = 65001 -pythonapi = None -if msvcrt: - import ctypes - (BOOL, DWORD, HANDLE, UINT) = (ctypes.c_long, ctypes.c_ulong, ctypes.c_void_p, ctypes.c_uint) - GetConsoleCP = ctypes.WINFUNCTYPE(UINT)(('GetConsoleCP', ctypes.windll.kernel32)) - SetConsoleCP = ctypes.WINFUNCTYPE(BOOL, UINT)(('SetConsoleCP', ctypes.windll.kernel32)) - GetConsoleOutputCP = ctypes.WINFUNCTYPE(UINT)(('GetConsoleOutputCP', ctypes.windll.kernel32)) - SetConsoleOutputCP = ctypes.WINFUNCTYPE(BOOL, UINT)(('SetConsoleOutputCP', ctypes.windll.kernel32)) - GetConsoleMode = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.POINTER(DWORD), use_last_error=True)(('GetConsoleMode', ctypes.windll.kernel32)) - GetNumberOfConsoleInputEvents = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.POINTER(DWORD), use_last_error=True)(('GetNumberOfConsoleInputEvents', ctypes.windll.kernel32)) - ReadConsoleW = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.c_void_p, DWORD, ctypes.POINTER(DWORD), ctypes.c_void_p, use_last_error=True)(('ReadConsoleW', ctypes.windll.kernel32)) - WriteConsoleW = ctypes.WINFUNCTYPE(BOOL, HANDLE, ctypes.c_void_p, DWORD, ctypes.POINTER(DWORD), ctypes.c_void_p, use_last_error=True)(('WriteConsoleW', ctypes.windll.kernel32)) - class Py_buffer(ctypes.Structure): _fields_ = [('buf', ctypes.c_void_p), ('obj', ctypes.py_object), ('len', ctypes.c_ssize_t), ('itemsize', ctypes.c_ssize_t), ('readonly', ctypes.c_int), ('ndim', ctypes.c_int), ('format', ctypes.c_char_p), ('shape', ctypes.POINTER(ctypes.c_ssize_t)), ('strides', ctypes.POINTER(ctypes.c_ssize_t)), ('suboffsets', ctypes.POINTER(ctypes.c_ssize_t))] + ([('smalltable', ctypes.c_ssize_t * 2)] if sys.version_info[0] <= 2 else []) + [('internal', ctypes.c_void_p)] - try: from ctypes import pythonapi - except ImportError: pass -if pythonapi: - def getbuffer(b, writable): - arr = Py_buffer() - pythonapi.PyObject_GetBuffer(ctypes.py_object(b), ctypes.byref(arr), ctypes.c_int(writable)) - try: buf = (ctypes.c_ubyte * arr.len).from_address(arr.buf) - finally: pythonapi.PyBuffer_Release(ctypes.byref(arr)) - return buf - -ENCODING = 'utf-8' - -if sys.version_info[0] < 3: - class NotASurrogateError(Exception): pass - def surrogateescape_handler(exc): - # Source: https://github.com/PythonCharmers/python-future/blob/aef57391c0cd58bf840dff5e2bc2c8c0f5b0a1b4/src/future/utils/surrogateescape.py - mystring = exc.object[exc.start:exc.end] - try: - if isinstance(exc, UnicodeDecodeError): - decoded = [] - for ch in mystring: - if isinstance(ch, int): - code = ch - else: - code = ord(ch) - if 0x80 <= code <= 0xFF: - decoded.append(unichr(0xDC00 + code)) - elif code <= 0x7F: - decoded.append(unichr(code)) - else: - raise NotASurrogateError() - decoded = str().join(decoded) - elif isinstance(exc, UnicodeEncodeError): - decoded = [] - for ch in mystring: - code = ord(ch) - if not 0xD800 <= code <= 0xDCFF: - raise NotASurrogateError() - if 0xDC00 <= code <= 0xDC7F: - decoded.append(unichr(code - 0xDC00)) - elif code <= 0xDCFF: - decoded.append(unichr(code - 0xDC00)) - else: - raise NotASurrogateError() - decoded = str().join(decoded) - else: - raise exc - except NotASurrogateError: - raise exc - return (decoded, exc.end) - codecs.register_error('surrogateescape', surrogateescape_handler) - -def exception_encode(ex, codec): - if str == bytes: - reduced = ex.__reduce__() - ex = reduced[0](*tuple(map(lambda arg: codec.decode(arg)[0] if isinstance(arg, bytes) else arg, reduced[1]))) - return ex - -def sql_commands(read_line): - delims = ['"', "'", ';', '--'] - counter = 0 - in_string = None - j = i = 0 - prev_line = None - line = None - concat = [] - while True: - if line is None: - while True: # process preprocessor directives - counter += 1 - not_in_the_middle_of_any_input = not in_string and i == j and all(map(lambda chunk_: len(chunk_) == 0, concat)) - line = read_line(counter - 1, not_in_the_middle_of_any_input, prev_line) - empty_string = line[:0] if line is not None else line - prev_line = line - if not line: - break - if not_in_the_middle_of_any_input and line.startswith("."): - yield line - line = None - else: - break - if not line: - break - j = i = 0 - if j < len(line): - (j, delim) = min(map(lambda pair: pair if pair[0] >= 0 else (len(line), pair[1]), map(lambda d: (line.find(d, j), d), in_string or delims if in_string != '--' else "\n"))) - if i < j: concat.append(line[i:j]); i = j - if not in_string: - if j < len(line): - j += len(delim) - if delim == ';': - i = j - concat.append(line[j : j + len(delim)]) # ensure delimeter is the same type as the string (it may not be due to implicit conversion) - # Eat up any further spaces until a newline - while j < len(line): - delim = line[j:j+1] - if not delim.isspace(): break - j += 1 - if delim == "\n": break - if i < j: concat.append(line[i:j]); i = j - yield empty_string.join(concat) - del concat[:] - else: - in_string = delim - else: - if j < len(line): - ch = line[j:j+1] - assert ch == in_string or in_string == '--' - j += 1 - i = j - concat.append(ch) - in_string = None - else: - if i < j: concat.append(line[i:j]); i = j - line = None - -class WindowsConsoleIOMixin(object): - # Ctrl+C handling with ReadFile() is messed up on Windows starting on Windows 8... here's some background reading: - # https://stackoverflow.com/a/43260436 - # https://github.com/microsoft/terminal/issues/334 - # We use ReadConsole when we can, so it doesn't affect us, but it's good info to know regardless. - def __init__(self, fd): - assert isatty(fd), "file descriptor must refer to a console (note that on Windows, NUL satisfies isatty(), but is not a console)" - self.fd = fd - self.handle = msvcrt.get_osfhandle(fd) - def fileno(self): return self.fd - def isatty(self): return isatty(self.fd) - def seekable(self): return False - def readable(self): return GetNumberOfConsoleInputEvents(self.handle, ctypes.byref(DWORD(0))) != 0 - def writable(self): n = DWORD(0); return WriteConsoleW(self.handle, ctypes.c_void_p(), n, ctypes.byref(n), ctypes.c_void_p()) != 0 - def readwcharsinto(self, buf, n): - nr = DWORD(n) - old_error = ctypes.get_last_error() - ctypes.set_last_error(0) - success = ReadConsoleW(self.handle, buf, nr, ctypes.byref(nr), ctypes.c_void_p()) - error = ctypes.get_last_error() - ctypes.set_last_error(old_error) - if not success: raise ctypes.WinError(error) - ERROR_OPERATION_ABORTED = 995 - if nr.value == 0 and error == ERROR_OPERATION_ABORTED: - # Apparently this can trigger pending KeyboardInterrupts? - time.sleep(1.0 / (1 << 64)) - raise KeyboardInterrupt() # If Python doesn't raise it, we can - return nr.value - def writewchars(self, buf, n): - nw = DWORD(n) - if not WriteConsoleW(self.handle, buf, nw, ctypes.byref(nw), ctypes.c_void_p()): - raise ctypes.WinError() - return nw.value - -class WindowsConsoleRawIO(WindowsConsoleIOMixin, io.RawIOBase): - def readinto(self, b): - wordsize = ctypes.sizeof(ctypes.c_wchar) - return self.readwcharsinto(getbuffer(b, True), len(b) // wordsize) * wordsize - def write(self, b): - wordsize = ctypes.sizeof(ctypes.c_wchar) - return self.writewchars(getbuffer(b, False), len(b) // wordsize) * wordsize - -class WindowsConsoleTextIO(WindowsConsoleIOMixin, io.TextIOBase): - buf = None - buffered = unicode() - translate = True - def getbuf(self, ncodeunits): - buf = self.buf - if buf is None or len(buf) < ncodeunits: - self.buf = buf = ctypes.create_unicode_buffer(ncodeunits) - return buf - @staticmethod # Don't let classes override this... they can override the caller instead - def do_read(self, nchars, translate_newlines): - prenewline = os.linesep[:-1] - newline = os.linesep[-1:] - empty = os.linesep[:0] - if nchars is None or nchars < -1: nchars = -1 - ncodeunits = nchars if nchars >= 0 else io.DEFAULT_BUFFER_SIZE # Unit mismatch, but doesn't matter; we'll loop - buf = None - istart = 0 - while True: - iend = self.buffered.find(newline, istart, min(istart + nchars, len(self.buffered)) if nchars >= 0 else None) if newline is not None else nchars - if iend >= 0: iend += len(newline) if newline is not None else 0 - if 0 <= iend <= len(self.buffered): - break - if buf is None: buf = self.getbuf(ncodeunits) - istart = len(self.buffered) - chunk = buf[:self.readwcharsinto(buf, ncodeunits)] - if translate_newlines: chunk = chunk.replace(prenewline, empty) - if chunk.startswith('\x1A'): # EOF on Windows (Ctrl+Z) at the beginning of a line results in the entire rest of the buffer being discarded - iend = istart - break - # Python 2 and Python 3 behaviors differ on Windows... Python 2's sys.stdin.readline() just deletes the next character if it sees EOF in the middle of a string! I won't emulate that here. - self.buffered += chunk # We're relying on Python's concatenation optimization here... we don't do it ourselves, since we want self.buffered to be valid every iteration in case there is an exception raised - result = self.buffered[:iend] - self.buffered = self.buffered[iend:] - return result - def read(self, nchars=-1): return WindowsConsoleTextIO.do_read(self, nchars, None, self.translate) - def readline(self, nchars=-1): return WindowsConsoleTextIO.do_read(self, nchars, self.translate) - def write(self, text): buf = ctypes.create_unicode_buffer(text); return self.writewchars(buf, max(len(buf) - 1, 0)) - -def wrap_windows_console_io(stream, is_output): - fd = None - if stream is not None and sys.version_info[0] < 3 and msvcrt and (is_output or pythonapi) and isatty(stream): - try: fd = stream.fileno() - except io.UnsupportedOperation: pass - result = stream - if fd is not None: - f = GetConsoleOutputCP if is_output else GetConsoleCP - if not f or f() != CP_UTF8: - try: - if True or is_output: - result = WindowsConsoleTextIO(fd) - else: - result = io.TextIOWrapper((io.BufferedWriter if is_output else io.BufferedReader)(WindowsConsoleRawIO(fd)), 'utf-16-le', 'strict', line_buffering=True) - except IOError: pass - return result - -class NonOwningTextIOWrapper(io.TextIOWrapper): - def __init__(self, base_textiowrapper, **kwargs): - assert isinstance(base_textiowrapper, io.TextIOWrapper) - self.base = base_textiowrapper # must keep a reference to this alive so it doesn't get closed - super(NonOwningTextIOWrapper, self).__init__(base_textiowrapper.buffer, **kwargs) - def close(self): - super(NonOwningTextIOWrapper, self).flush() - -def wrap_unicode_stdio(stream, is_writer, encoding): # The underlying stream must NOT be used directly until the stream returned by this function is disposed of - if isinstance(stream, io.TextIOWrapper): - stream.flush() # Make sure nothing is left in the buffer before we re-wrap it - none = object() - kwargs = {} - for key in ['encoding', 'errors', 'newline', 'line_buffering', 'write_through']: - value = getattr(stream, 'newlines' if key == 'newline' else key, none) - if value is not none: - kwargs[key] = value - kwargs['encoding'] = encoding - result = NonOwningTextIOWrapper(stream, **kwargs) - elif 'PYTHONIOENCODING' not in os.environ and str == bytes and stream in (sys.stdin, sys.stdout, sys.stderr): - result = (codecs.getwriter if is_writer else codecs.getreader)(encoding)(stream) - else: - result = stream - return result - -class StringEscapeParser(object): - def __init__(self): - import re - self.pattern = re.compile("\"((?:[^\"\\n]+|\\\\.)*)(?:\"|$)|\'([^\'\\n]*)(?:\'|$)|(\\S+)") - self.escape_pattern = re.compile("\\\\(.)", re.DOTALL) - @staticmethod - def escape_replacement(m): - text = m.group(1) - if text == "\\": text = "\\" - elif text == "/": text = "\n" - elif text == "n": text = "\n" - elif text == "r": text = "\r" - elif text == "t": text = "\t" - elif text == "v": text = "\v" - elif text == "f": text = "\f" - elif text == "a": text = "\a" - elif text == "b": text = "\b" - return text - def __call__(self, s): - escape_pattern = self.escape_pattern - escape_replacement = self.escape_replacement - result = [] - for match in self.pattern.finditer(s): - [m1, m2, m3] = match.groups() - if m1 is not None: result.append(escape_pattern.sub(escape_replacement, m1)) - if m2 is not None: result.append(m2) - if m3 is not None: result.append(escape_pattern.sub(escape_replacement, m3)) - return result - -class Database(object): - def __init__(self, name, *args, **kwargs): - self.connection = sqlite3.connect(name, *args, **kwargs) - self.cursor = self.connection.cursor() - self.name = name # assign name only AFTER cursor is created - -def isatty(file_or_fd): - result = True - method = getattr(file_or_fd, 'isatty', None) if not isinstance(file_or_fd, int) else None # this check is just an optimization - if method is not None: - try: tty = method() - except io.UnsupportedOperation: tty = None - result = result and tty is not None and tty - method = getattr(file_or_fd, 'fileno', None) if not isinstance(file_or_fd, int) else None # this check is just an optimization - if method is not None: - try: fd = method() - except io.UnsupportedOperation: fd = None - result = result and fd is not None and os.isatty(fd) and (not msvcrt or GetConsoleMode(msvcrt.get_osfhandle(fd), ctypes.byref(DWORD(0))) != 0) - return result - -def can_call_input_for_stdio(stream): - return stream == sys.stdin and sys.version_info[0] >= 3 - -class StdIOProxy(object): - # Maybe useful later: codecs.StreamRecoder(bytesIO, codec.decode, codec.encode, codec.streamwriter, codec.streamreader, errors='surrogateescape') - def __init__(self, stdin, stdout, stderr, codec, allow_set_code_page): - self.codec = codec - streams = (stdin, stdout, stderr) - for stream in streams: - assert isinstance(stream, io.IOBase) or sys.version_info[0] < 3 and isinstance(stream, file) or hasattr(stream, 'mode'), "unable to determine stream type" - assert not isinstance(stream, io.RawIOBase), "RAW I/O APIs are different and not supported" - self.streaminfos = tuple(map(lambda stream: - ( - stream, - isinstance(stream, io.BufferedIOBase) or isinstance(stream, io.RawIOBase) or not isinstance(stream, io.TextIOBase) and 'b' in stream.mode, - isinstance(stream, io.TextIOBase) or not (isinstance(stream, io.BufferedIOBase) or isinstance(stream, io.RawIOBase)) and 'b' not in stream.mode, - allow_set_code_page - ), - streams)) - @property - def stdin(self): return self.streaminfos[0][0] - @property - def stdout(self): return self.streaminfos[1][0] - @property - def stderr(self): return self.streaminfos[2][0] - def _coerce(self, streaminfo, codec, arg): - stream = streaminfo[0] - can_binary = streaminfo[1] - can_text = streaminfo[2] - if not isinstance(arg, bytes) and not isinstance(arg, buffer) and not isinstance(arg, unicode): - arg = unicode(arg) - if isinstance(arg, bytes) or isinstance(arg, buffer): - if not can_binary: - arg = codec.decode(arg, 'surrogateescape')[0] - elif isinstance(arg, unicode): - if not can_text: - arg = codec.encode(unicode(arg), 'strict')[0] - return arg - @staticmethod - def _do_readline(stream, allow_set_code_page, *args): - new_code_page = CP_UTF8 - old_code_page = GetConsoleCP() if msvcrt and GetConsoleCP and isatty(stream) else None - if old_code_page == new_code_page: old_code_page = None # Don't change code page if it's already correct... - if old_code_page is not None: - if not SetConsoleCP(new_code_page): - old_code_page = None - try: - result = stream.readline(*args) - finally: - if old_code_page is not None: - SetConsoleCP(old_code_page) - return result - @staticmethod - def _do_write(stream, allow_set_code_page, *args): - new_code_page = CP_UTF8 - old_code_page = GetConsoleOutputCP() if msvcrt and GetConsoleOutputCP and isatty(stream) else None - if old_code_page == new_code_page: old_code_page = None # Don't change code page if it's already correct... - if old_code_page is not None: - if not SetConsoleOutputCP(new_code_page): - old_code_page = None - try: - result = stream.write(*args) - finally: - if old_code_page is not None: - SetConsoleCP(old_code_page) - return result - def _readln(self, streaminfo, codec, prompt): - stream = streaminfo[0] - can_binary = streaminfo[1] - allow_set_code_page = streaminfo[3] - if can_call_input_for_stdio(stream) and not can_binary: # input() can't work with binary data - result = self._coerce(streaminfo, codec, "") - try: - result = input(*((self._coerce(streaminfo, codec, prompt),) if prompt is not None else ())) - result += self._coerce(streaminfo, codec, "\n") - except EOFError: pass - else: - self.output(*((prompt,) if prompt is not None else ())) - self.error() - result = StdIOProxy._do_readline(stream, allow_set_code_page) - return result - def _writeln(self, streaminfo, codec, *args, **kwargs): - stream = streaminfo[0] - allow_set_code_page = streaminfo[3] - flush = kwargs.pop('flush', True) - kwargs.setdefault('end', '\n') - kwargs.setdefault('sep', ' ') - end = kwargs.get('end') - sep = kwargs.get('sep') - first = True - for arg in args: - if first: first = False - elif sep is not None: - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, sep)) - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, arg)) - if end is not None: - StdIOProxy._do_write(stream, allow_set_code_page, self._coerce(streaminfo, codec, end)) - if flush: stream.flush() - def inputln(self, prompt=None): return self._readln(self.streaminfos[0], self.codec, prompt) - def output(self, *args, **kwargs): kwargs.setdefault('end', None); return self._writeln(self.streaminfos[1], self.codec, *args, **kwargs) - def outputln(self, *args, **kwargs): return self._writeln(self.streaminfos[1], self.codec, *args, **kwargs) - def error(self, *args, **kwargs): kwargs.setdefault('end', None); return self._writeln(self.streaminfos[2], self.codec, *args, **kwargs) - def errorln(self, *args, **kwargs): return self._writeln(self.streaminfos[2], self.codec, *args, **kwargs) - -class bytes_comparable_with_unicode(bytes): # For Python 2/3 compatibility, to allow implicit conversion between strings and bytes when it is safe. (Used for strings like literals which we know be safe.) - codec = codecs.lookup('ascii') # MUST be a safe encoding - @classmethod - def coerce(cls, other, for_output=False): - return cls.codec.encode(other)[0] if not isinstance(other, bytes) else bytes_comparable_with_unicode(other) if for_output else other - @classmethod - def translate_if_bytes(cls, value): - if value is not None and isinstance(value, bytes): value = cls(value) - return value - def __hash__(self): return super(bytes_comparable_with_unicode, self).__hash__() # To avoid warning - def __eq__(self, other): return super(bytes_comparable_with_unicode, self).__eq__(self.coerce(other)) - def __ne__(self, other): return super(bytes_comparable_with_unicode, self).__ne__(self.coerce(other)) - def __lt__(self, other): return super(bytes_comparable_with_unicode, self).__lt__(self.coerce(other)) - def __gt__(self, other): return super(bytes_comparable_with_unicode, self).__gt__(self.coerce(other)) - def __le__(self, other): return super(bytes_comparable_with_unicode, self).__le__(self.coerce(other)) - def __ge__(self, other): return super(bytes_comparable_with_unicode, self).__ge__(self.coerce(other)) - def __getitem__(self, index): return self.coerce(super(bytes_comparable_with_unicode, self).__getitem__(index), True) - def __add__(self, other): return self.coerce(super(bytes_comparable_with_unicode, self).__add__(self.coerce(other)), True) - def __iadd__(self, other): return self.coerce(super(bytes_comparable_with_unicode, self).__iadd__(self.coerce(other)), True) - def __radd__(self, other): return self.coerce(self.coerce(other).__add__(self), True) - def find(self, other, *args): return super(bytes_comparable_with_unicode, self).find(self.coerce(other), *args) - def join(self, others): return self.coerce(super(bytes_comparable_with_unicode, self).join(map(self.coerce, others)), True) - def startswith(self, other): return super(bytes_comparable_with_unicode, self).startswith(self.coerce(other)) - def __str__(self): return self.codec.decode(self)[0] - if str == bytes: - __unicode__ = __str__ - def __str__(self): raise NotImplementedError() - -def wrap_bytes_comparable_with_unicode_readline(readline): - def callback(*args): - line = readline(*args) - line = bytes_comparable_with_unicode.translate_if_bytes(line) - return line - return callback - -def main(program, *args, **kwargs): # **kwargs = dict(stdin=file, stdout=file, stderr=file); useful for callers who import this module - import argparse # slow import (compiles regexes etc.), so don't import it until needed - argparser = argparse.ArgumentParser( - prog=os.path.basename(program), - usage=None, - description=None, - epilog=None, - parents=[], - formatter_class=argparse.RawTextHelpFormatter) - argparser.add_argument('-version', '--version', action='store_true', help="show SQLite version") - argparser.add_argument('-batch', '--batch', action='store_true', help="force batch I/O") - argparser.add_argument('-init', '--init', metavar="FILE", help="read/process named file") - argparser.add_argument('filename', nargs='?', metavar="FILENAME", help="is the name of an SQLite database.\nA new database is created if the file does not previously exist.") - argparser.add_argument('sql', nargs='*', metavar="SQL", help="SQL commnds to execute after opening database") - argparser.add_argument('--readline', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to import readline if available (default: %(default)s)") - argparser.add_argument('--self-test', action='store_true', help="perform a basic self-test") - argparser.add_argument('--cross-test', action='store_true', help="perform a basic test against the official executable") - argparser.add_argument('--unicode-stdio', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to enable Unicode wrapper for standard I/O (default: %(default)s)") - argparser.add_argument('--console', action='store', metavar="(true|false)", default="true", choices=("true", "false"), help="whether to auto-detect and use console window APIs (default: %(default)s)") - argparser.add_argument('--encoding', default=ENCODING, help="the default encoding to use (default: %(default)s)") - (stdin, stdout, stderr) = (kwargs.pop('stdin', sys.stdin), kwargs.pop('stdout', sys.stdout), kwargs.pop('stderr', sys.stderr)) - parsed_args = argparser.parse_args(args) - codec = codecs.lookup(parsed_args.encoding or argparser.get_default('encoding')) - if parsed_args.self_test: self_test(codec) - if parsed_args.cross_test: cross_test("sqlite3", codec) - parse_escaped_strings = StringEscapeParser() - if parsed_args.unicode_stdio == "true": - stdin = wrap_unicode_stdio(stdin, False, codec.name) - stdout = wrap_unicode_stdio(stdout, True, codec.name) - stderr = wrap_unicode_stdio(stderr, True, codec.name) - if parsed_args.console == "true": - stdin = wrap_windows_console_io(stdin, False) - stdout = wrap_windows_console_io(stdout, True) - stderr = wrap_windows_console_io(stderr, True) - allow_set_code_page = sys.version_info[0] < 3 and False # This is only necessary on Python 2 if we use the default I/O functions instead of bypassing to ReadConsole()/WriteConsole() - stdio = StdIOProxy(stdin, stdout, stderr, codec, allow_set_code_page) - db = None - no_args = len(args) == 0 - init_sql = parsed_args.sql - is_nonpipe_input = stdin.isatty() # NOT the same thing as TTY! (NUL and /dev/null are the difference) - init_show_prompt = not parsed_args.batch and is_nonpipe_input - if not parsed_args.batch and isatty(stdin) and (parsed_args.readline == "true" or __name__ == '__main__') and parsed_args.readline != "false": - try: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore', category=DeprecationWarning) - import readline - except ImportError: pass - if parsed_args and parsed_args.version: - stdio.outputln(sqlite3.sqlite_version); - else: - filename = parsed_args.filename - if filename is None: filename = ":memory:" - db = Database(filename, isolation_level=None) - def exec_script(db, filename, ignore_io_errors): - try: - with io.open(filename, 'r', encoding=codec.name) as f: # Assume .sql files are text -- any binary data inside them should be X'' encoded, not embedded directly - for command in sql_commands(wrap_bytes_comparable_with_unicode_readline(lambda *args: (lambda s: (s) or None)(f.readline()))): - result = exec_command(db, command, False and ignore_io_errors) - if result is not None: - return result - except IOError as ex: - stdio.errorln(ex) - if not ignore_io_errors: return ex.errno - def raise_invalid_command_error(command): - if isinstance(command, bytes): command = codec.decode(command)[0] - if command.startswith("."): command = command[1:] - raise RuntimeError("Error: unknown command or invalid arguments: \"%s\". Enter \".help\" for help" % (command.rstrip().replace("\\", "\\\\").replace("\"", "\\\""),)) - def exec_command(db, command, ignore_io_errors): - results = None - query = None - query_parameters = {} - try: - if command.startswith("."): - args = list(parse_escaped_strings(command)) - if args[0] in (".quit", ".exit"): - return 0 - elif args[0] == ".help": - stdio.error(""" -.cd DIRECTORY Change the working directory to DIRECTORY -.dump Dump the database in an SQL text format -.exit Exit this program -.help Show this message -.open FILE Close existing database and reopen FILE -.print STRING... Print literal STRING -.quit Exit this program -.read FILENAME Execute SQL in FILENAME -.schema ?PATTERN? Show the CREATE statements matching PATTERN -.show Show the current values for various settings -.tables ?TABLE? List names of tables -""".lstrip()) - elif args[0] == ".cd": - if len(args) != 2: raise_invalid_command_error(command) - os.chdir(args[1]) - elif args[0] == ".dump": - if len(args) != 1: raise_invalid_command_error(command) - foreign_keys = db.cursor.execute("PRAGMA foreign_keys;").fetchone()[0] - if foreign_keys in (0, "0", "off", "OFF"): - stdio.outputln("PRAGMA foreign_keys=OFF;", flush=False) - for line in db.connection.iterdump(): - stdio.outputln(line, flush=False) - stdio.output() - elif args[0] == ".open": - if len(args) <= 1: raise_invalid_command_error(command) - filename = args[-1] - for option in args[+1:-1]: - raise ValueError("option %s not supported" % (repr(option),)) - try: db.__init__(filename) - except sqlite3.OperationalError as ex: - ex.args = ex.args[:0] + ("Error: unable to open database \"%s\": %s" % (filename, ex.args[0]),) + ex.args[1:] - raise - elif args[0] == ".print": - stdio.outputln(*args[1:]) - elif args[0] == ".read": - if len(args) != 2: raise_invalid_command_error(command) - exec_script(db, args[1], ignore_io_errors) - elif args[0] == ".schema": - if len(args) > 2: raise_invalid_command_error(command) - pattern = args[1] if len(args) > 1 else None - query_parameters['type'] = 'table' - if pattern is not None: - query_parameters['pattern'] = pattern - query = "SELECT sql || ';' FROM sqlite_master WHERE type = :type" + (" AND name LIKE :pattern" if pattern is not None else "") + ";" - elif args[0] == ".show": - if len(args) > 2: raise_invalid_command_error(command) - stdio.errorln(" filename:", db.name) - elif args[0] == ".tables": - if len(args) > 2: raise_invalid_command_error(command) - pattern = args[1] if len(args) > 1 else None - query_parameters['type'] = 'table' - if pattern is not None: - query_parameters['pattern'] = pattern - query = "SELECT name FROM sqlite_master WHERE type = :type" + (" AND name LIKE :pattern" if pattern is not None else "") + ";" - else: - raise_invalid_command_error(args[0]) - else: - query = command - if query is not None: - results = db.cursor.execute(query if isinstance(query, unicode) else codec.decode(query, 'surrogatereplace')[0], query_parameters) - except (RuntimeError, OSError, FileNotFoundError, sqlite3.OperationalError) as ex: - stdio.errorln(exception_encode(ex, codec)) - if results is not None: - for row in results: - stdio.outputln(*tuple(map(lambda item: item if item is not None else "", row)), sep="|", flush=False) - stdio.output() - if db: - if parsed_args and parsed_args.init: - if is_nonpipe_input: stdio.errorln("-- Loading resources from", parsed_args.init) - exec_script(db, parsed_args.init, False) - def read_stdin(index, not_in_the_middle_of_any_input, prev_line): - show_prompt = init_show_prompt - to_write = [] - if index < len(init_sql): - line = init_sql[index] - if not line.startswith(".") and not line.rstrip().endswith(";"): - line += ";" - elif index == len(init_sql) and len(init_sql) > 0: - line = None - else: - if show_prompt: - if not_in_the_middle_of_any_input: - show_prompt = False - if index == 0: - to_write.append("SQLite version %s (adapter version %s)\nEnter \".help\" for usage hints.\n" % (sqlite3.sqlite_version, sqlite3.version)) - if no_args: - to_write.append("Connected to a transient in-memory database.\nUse \".open FILENAME\" to reopen on a persistent database.\n") - if index > 0 and not prev_line: - to_write.append("\n") - to_write.append("%7s " % ("sqlite%s>" % ("",) if not_in_the_middle_of_any_input else "...>",)) - try: - line = stdio.inputln("".join(to_write)) - except KeyboardInterrupt: - line = "" - raise # just kidding, don't handle it for now... - return line - for command in sql_commands(wrap_bytes_comparable_with_unicode_readline(read_stdin)): - result = exec_command(db, command, True) - if result is not None: - return result - if init_show_prompt and len(init_sql) == 0: - stdio.outputln() - -def call_program(cmdline, input_text): - import subprocess - return subprocess.Popen(cmdline, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=False).communicate(input_text) - -def test_query(): - hexcodec = codecs.lookup('hex_codec') - ascii = 'ascii' - data1 = b"\xD8\xA2" - data2 = b"\x01\x02\xFF\x01\xFF\xFE\xFD" - values = [data1, data2] - query_bytes = b'SELECT %s;' % (b", ".join(map(lambda b: b"X'%s'" % (hexcodec.encode(b)[0].upper(),), values)),) - expected_bytes = b"%s\n" % (b"|".join(values),) - return query_bytes, expected_bytes - -def cross_test(sqlite_cmdline, codec): - (query_bytes, expected_bytes) = test_query() - (official_output, official_error) = call_program(sqlite_cmdline, query_bytes) - # We can't use os.linesep here since binaries may belong to different platforms (Win32/MinGW vs. MSYS/Cygwin vs. WSL...) - official_output = official_output.replace(b"\r\n", b"\n") - official_error = official_error.replace(b"\r\n", b"\n") - if official_output != expected_bytes: - raise sqlite3.ProgrammingError("expected bytes are wrong: official %s != expected %s" % (repr(official_output), repr(expected_bytes))) - if official_error: - raise sqlite3.ProgrammingError("did not expect errors from official binary") - -def self_test(codec): - (query_bytes, expected_bytes) = test_query() - if not (lambda stdin, stdout, stderr: not main(sys.argv[0], stdin=stdin, stdout=stdout, stderr=stderr) and stdout.getvalue() == expected_bytes)(io.BytesIO(query_bytes), io.BytesIO(), io.BytesIO()): - raise sqlite3.ProgrammingError("byte I/O is broken") - if not (lambda stdin, stdout, stderr: not main(sys.argv[0], stdin=stdin, stdout=stdout, stderr=stderr) and stdout.getvalue() == codec.decode(expected_bytes, 'surrogateescape'))(io.StringIO(query_bytes.decode(ascii)), io.StringIO(), io.StringIO()): - raise sqlite3.ProgrammingError("string I/O is broken") - -if __name__ == '__main__': - import sys - exit_code = main(*sys.argv) - if exit_code not in (None, 0): raise SystemExit(exit_code) diff --git a/hw/hw10/tests/by_parent_height.py b/hw/hw10/tests/by_parent_height.py deleted file mode 100644 index 952f037265..0000000000 --- a/hw/hw10/tests/by_parent_height.py +++ /dev/null @@ -1,32 +0,0 @@ -test = { - 'name': 'by_parent_height', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM by_parent_height; - herbert - fillmore - abraham - delano - grover - barack - clinton - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': True, - 'scored': True, - 'setup': r""" - sqlite> .read hw10.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw10/tests/low_variance.py b/hw/hw10/tests/low_variance.py deleted file mode 100644 index 3093497936..0000000000 --- a/hw/hw10/tests/low_variance.py +++ /dev/null @@ -1,26 +0,0 @@ -test = { - 'name': 'low_variance', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM low_variance; - curly|1 - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw10.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw10/tests/sentences.py b/hw/hw10/tests/sentences.py deleted file mode 100644 index 9ee3e2035a..0000000000 --- a/hw/hw10/tests/sentences.py +++ /dev/null @@ -1,27 +0,0 @@ -test = { - 'name': 'sentences', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT * FROM sentences; - The two siblings, barack and clinton, have the same size: standard - The two siblings, abraham and grover, have the same size: toy - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw10.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw10/tests/size_of_dogs.py b/hw/hw10/tests/size_of_dogs.py deleted file mode 100644 index 0715bd75ed..0000000000 --- a/hw/hw10/tests/size_of_dogs.py +++ /dev/null @@ -1,30 +0,0 @@ -test = { - 'name': 'size_of_dogs', - 'points': 1, - 'suites': [ - { - 'cases': [ - { - 'code': r""" - sqlite> SELECT name FROM size_of_dogs WHERE size="toy" OR size="mini"; - abraham - eisenhower - fillmore - grover - herbert - """, - 'hidden': False, - 'locked': False, - 'multiline': False - } - ], - 'ordered': False, - 'scored': True, - 'setup': r""" - sqlite> .read hw10.sql - """, - 'teardown': '', - 'type': 'sqlite' - } - ] -} diff --git a/hw/hw11/hw11.ok b/hw/hw11/hw11.ok deleted file mode 100644 index d89574e462..0000000000 --- a/hw/hw11/hw11.ok +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "Homework 11", - "endpoint": "cal/cs61a/fa24/hw11", - "src": [ - "hw11.scm" - ], - "tests": { - "tests/*.py": "ok_test" - }, - "protocols": [ - "restore", - "file_contents", - "unlock", - "grading", - "analytics", - "backup" - ] -} \ No newline at end of file diff --git a/hw/hw11/hw11.py b/hw/hw11/hw11.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/hw/hw11/hw11.zip b/hw/hw11/hw11.zip deleted file mode 100644 index 7cb46bf349..0000000000 Binary files a/hw/hw11/hw11.zip and /dev/null differ diff --git a/hw/hw11/index.html b/hw/hw11/index.html deleted file mode 100644 index ae367f12df..0000000000 --- a/hw/hw11/index.html +++ /dev/null @@ -1,284 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Homework 11 | CS 61A Fall 2024 - - - - - - -
- -
-
-
-

- -Homework 11: Finale - - -

-
- - -

Due by 11:59pm on Sunday, December 15

- - - - -

This homework has nothing you need to submit to Gradescope. Rather, there are 3 surveys you need to fill out.

- - - -

If 80% or more students (computed as the fraction of the number of students who took Midterm 2) -complete all three, then all students who complete this homework get an extra credit point!

- - - - -
- -
- -
-
- -
- - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/hw/hw11/ok b/hw/hw11/ok deleted file mode 100644 index 0d2fead7a3..0000000000 Binary files a/hw/hw11/ok and /dev/null differ diff --git a/index.html b/index.html index 68c4fd126a..9ff7e06ec9 100644 --- a/index.html +++ b/index.html @@ -506,13 +506,17 @@

Calendar


-Lab 03: Higher-Order Functions +Lab 03: Higher-Order Functions
Due Fri 9/20
+ +
@@ -559,6 +563,7 @@

Calendar

@@ -573,7 +578,7 @@

Calendar

Disc 04: Recursion @@ -612,7 +617,7 @@

Calendar

-HW 04: Recursion +HW 04: Recursion
Due Wed 10/2 @@ -1262,7 +1267,7 @@

Policies

+ + + + + + + + + + + + + + + + + + +Lab 3 Solutions | Data C88C Fall 2024 + + + + + + +
+ +
+
+
+

+ +Lab 3 Solutions + + + + + + +

+
+ +

Solution Files

+ + + +

Topics

+ + +

Consult this section if you need a refresher on the material for this lab. It's +okay to skip directly to the questions and refer back +here should you get stuck.

+ + + +
+ + +

Short Circuiting

+ + +

What do you think will happen if we type the following into Python?

+ +
1 / 0
+ +

Try it out in Python! You should see a ZeroDivisionError. But what about this expression?

+ +
True or 1 / 0
+ +

It evaluates to True because Python's and and or operators short-circuit. That is, they don't necessarily evaluate every operand.

+ +
+ + + + + + + + + + + + + + + + + + + +
OperatorChecks if:Evaluates from left to right up to:Example
ANDAll values are trueThe first false valueFalse and 1 / 0 evaluates to False
ORAt least one value is trueThe first true valueTrue or 1 / 0 evaluates to True
+
+ +

Short-circuiting happens when the operator reaches an operand that allows them to make a conclusion about the expression. For example, and will short-circuit as soon as it reaches the first false value because it then knows that not all the values are true.

+ +

If and and or do not short-circuit, they just return the last +value; another way to remember this is that and and or always return the last +thing they evaluate, whether they short circuit or not. Keep in mind that and and or +don't always return booleans when using values other than True and False.

+ +
+ + + +
+ + +

Higher-Order Functions

+ + +

Variables are names bound to values, which can be primitives like 3 or +'Hello World', but they can also be functions. And since functions can take +arguments of any value, other functions can be passed in as arguments. This is +the basis for higher-order functions.

+ +

A higher order function is a function that manipulates other functions by +taking in functions as arguments, returning a function, or both. We will +introduce the basics of higher order functions in this lab and will be +exploring many applications of higher order functions in our next lab.

+ + +

Functions as arguments

+ + +

In Python, function objects are values that can be passed around. We know that one +way to create functions is by using a def statement:

+ +
def square(x):
+    return x * x
+ +

The above statement created a function object with the intrinsic name square as +well as binded it to the name square in the current environment. Now let's try +passing it as an argument.

+ +

First, let's write a function that takes in another function as an argument:

+ +
def scale(f, x, k):
+    """ Returns the result of f(x) scaled by k. """
+    return k * f(x)
+ +

We can now call scale on square and some other arguments:

+ +
>>> scale(square, 3, 2) # Double square(3)
+18
+>>> scale(square, 2, 5) # 5 times 2 squared
+20
+ +

Note that in the body of the call to scale, the function object with the intrinsic +name square is bound to the parameter f. Then, we call square in the body of +scale by calling f(x).

+ +

As we saw in the above section on lambda expressions, we can also pass +lambda expressions into call expressions!

+ +
>>> scale(lambda x: x + 10, 5, 2)
+30
+ +

In the frame for this call expression, the name f is bound to the function +created by the lambda expression lambda x: x + 10.

+ + +

Functions that return functions

+ + +

Because functions are values, they are valid as return values! Here's an example:

+ +
def multiply_by(m):
+    def multiply(n):
+        return n * m
+    return multiply
+ +

In this particular case, we defined the function multiply within the body of multiply_by +and then returned it. Let's see it in action:

+ +
>>> multiply_by(3)
+<function multiply_by.<locals>.multiply at ...>
+>>> multiply(4)
+Traceback (most recent call last):
+File "<stdin>", line 1, in <module>
+NameError: name 'multiply' is not defined
+ +

A call to multiply_by returns a function, as expected. However, calling +multiply errors, even though that's the name we gave the inner function. This +is because the name multiply only exists within the frame where we evaluate +the body of multiply_by.

+ +

So how do we actually use the inner function? Here are two ways:

+ +
>>> times_three = multiply_by(3) # Assign the result of the call expression to a name
+>>> times_three(5) # Call the inner function with its new name
+15
+>>> multiply_by(3)(10) # Chain together two call expressions
+30
+ +

The point is, because multiply_by returns a function, you can use its return +value just like you would use any other function.

+ + + +
+
+ + + +
+ + +

Lambda Expressions

+ + +

Lambda expressions are expressions that evaluate to functions by specifying two +things: the parameters and a return expression.

+ +
lambda <parameters>: <return expression>
+ +

While both lambda expressions and def statements create function objects, +there are some notable differences. lambda expressions work like other +expressions; much like a mathematical expression just evaluates to a number and +does not alter the current environment, a lambda expression +evaluates to a function without changing the current environment. Let's take a +closer look.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
lambdadef
TypeExpression that evaluates to a valueStatement that alters the environment
Result of executionCreates an anonymous lambda function with no intrinsic name.Creates a function with an intrinsic name and binds it to that + name in the current environment.
Effect on the environmentEvaluating a lambda expression does not create or + modify any variables.Executing a def statement both creates a new function + object and binds it to a name in the current environment.
UsageA lambda expression can be used anywhere that + expects an expression, such as in an assignment statement or as the + operator or operand to a call expression.After executing a def statement, the created + function is bound to a name. You should use this name to refer to the + function anywhere that expects an expression.
Example +
# A lambda expression by itself does not alter
+# the environment
+lambda x: x * x
+
+# We can assign lambda functions to a name
+# with an assignment statement
+square = lambda x: x * x
+square(3)
+
+# Lambda expressions can be used as an operator
+# or operand
+negate = lambda f, x: -f(x)
+negate(lambda x: x * x, 3)
def square(x):
+    return x * x
+
+# A function created by a def statement
+# can be referred to by its intrinsic name
+square(3)
+
+ + +

YouTube link

+ +
+ + + +
+ + +

Environment Diagrams

+ + +

Environment diagrams are one of the best learning tools for understanding +lambda expressions and higher order functions because you're able to keep +track of all the different names, function objects, and arguments to functions. +We highly recommend drawing environment diagrams or using Python +tutor if you get stuck doing the WWPD problems below. +For examples of what environment diagrams should look like, try running some +code in Python tutor. Here are the rules:

+ + +

Assignment Statements

+ + +
    +
  1. Evaluate the expression on the right hand side of the = sign.
  2. +
  3. If the name found on the left hand side of the = doesn't already exist in + the current frame, write it in. If it does, erase the current binding. Bind the + value obtained in step 1 to this name.
  4. +
+ +

If there is more than one name/expression in the statement, evaluate all the +expressions first from left to right before making any bindings.

+ + + + +

def Statements

+ + +
    +
  1. Draw the function object with its intrinsic name, formal parameters, and + parent frame. A function's parent frame is the frame in which the function was + defined.
  2. +
  3. If the intrinsic name of the function doesn't already exist in the current + frame, write it in. If it does, erase the current binding. Bind the newly + created function object to this name.
  4. +
+ + + + +

Call expressions

+ + +

Note: you do not have to go through this process for a built-in Python function like max or print.

+ +
    +
  1. Evaluate the operator, whose value should be a function.
  2. +
  3. Evaluate the operands left to right.
  4. +
  5. Open a new frame. Label it with the sequential frame number, the intrinsic + name of the function, and its parent.
  6. +
  7. Bind the formal parameters of the function to the arguments whose values you + found in step 2.
  8. +
  9. Execute the body of the function in the new environment.
  10. +
+ + + + +

Lambdas

+ + +

Note: As we saw in the lambda expression section above, lambda +functions have no intrinsic name. When drawing lambda functions in +environment diagrams, they are labeled with the name lambda or with the +lowercase Greek letter λ. This can get confusing when there are +multiple lambda functions in an environment diagram, so you can distinguish +them by numbering them or by writing the line number on which they were defined.

+ +
    +
  1. Draw the lambda function object and label it with λ, its formal + parameters, and its parent frame. A function's parent frame is the frame in + which the function was defined.
  2. +
+ +

This is the only step. We are including this section to emphasize the fact that +the difference between lambda expressions and def statements is that +lambda expressions do not create any new bindings in the environment.

+ + + + +

YouTube link

+ +
+ + +

Required Questions

+ + +
+ + +
+ + +

Getting Started Videos

+ + +

These videos may provide some helpful direction for tackling the coding +problems on this assignment.

+ +

To see these videos, you should be logged into your berkeley.edu email.

+ + +

YouTube link

+
+ + +

What Would Python Display?

+ + +

Important: +For all WWPD questions, type Function if you believe the answer is +<function...>, Error if it errors, and Nothing if nothing is displayed.

+ + +

Q1: WWPD: Higher-Order Functions

+ + +

Use Ok to test your knowledge with the following "What Would Python Display?" questions:

python3 ok -q hof-wwpd -u
+ +
+
+ +
>>> def cake():
+...    print('beets')
+...    def pie():
+...        print('sweets')
+...        return 'cake'
+...    return pie
+>>> chocolate = cake()
+
______
beets
+>>> chocolate +
______
Function
+>>> chocolate() +
______
sweets 'cake'
+>>> more_chocolate, more_cake = chocolate(), cake +
______
sweets
+>>> more_chocolate +
______
'cake'
+>>> def snake(x, y): +... if cake == more_cake: +... return chocolate +... else: +... return x + y +>>> snake(10, 20) +
______
Function
+>>> snake(10, 20)() +
______
30
+>>> cake = 'cake' +>>> snake(10, 20) +
______
30
+ + + + +

Coding Practice

+ + + +

Q2: Composite Identity Function

+ + +

Write a function that takes in two single-argument functions, f and g, and +returns another function that has a single parameter x. The returned +function should return True if f(g(x)) is equal to g(f(x)) and False +otherwise. You can assume the output of g(x) is a valid input for f and vice +versa.

+ + + +
def composite_identity(f, g):
+    """
+    Return a function with one parameter x that returns True if f(g(x)) is
+    equal to g(f(x)). You can assume the result of g(x) is a valid input for f
+    and vice versa.
+
+    >>> add_one = lambda x: x + 1        # adds one to x
+    >>> square = lambda x: x**2          # squares x [returns x^2]
+    >>> b1 = composite_identity(square, add_one)
+    >>> b1(0)                            # (0 + 1) ** 2 == 0 ** 2 + 1
+    True
+    >>> b1(4)                            # (4 + 1) ** 2 != 4 ** 2 + 1
+    False
+    """
+
return lambda x: f(g(x)) == g(f(x)) + + # Alternate solution: + def h(x): + return f(g(x)) == g(f(x)) + return h
+ +
+ +
+We must create a function to take x using lambda or def, then compare the two quantities. +
+ +

Use Ok to test your code:

python3 ok -q composite_identity
+ +
+ + +

Q3: Count Cond

+ + +

Consider the following implementations of count_fives and count_primes which +use the sum_digits and is_prime functions from earlier assignments:

+ +
def count_fives(n):
+    """Return the number of values i from 1 to n (including n)
+    where sum_digits(n * i) is 5.
+    >>> count_fives(10)  # Among 10, 20, 30, ..., 100, only 50 (10 * 5) has digit sum 5
+    1
+    >>> count_fives(50)  # 50 (50 * 1), 500 (50 * 10), 1400 (50 * 28), 2300 (50 * 46)
+    4
+    """
+    i = 1
+    count = 0
+    while i <= n:
+        if sum_digits(n * i) == 5:
+            count += 1
+        i += 1
+    return count
+
+def count_primes(n):
+    """Return the number of prime numbers up to and including n.
+    >>> count_primes(6)   # 2, 3, 5
+    3
+    >>> count_primes(13)  # 2, 3, 5, 7, 11, 13
+    6
+    """
+    i = 1
+    count = 0
+    while i <= n:
+        if is_prime(i):
+            count += 1
+        i += 1
+    return count
+ + + +

The implementations look quite similar! Generalize this logic by writing a +function count_cond, which takes in a two-argument predicate function +condition(n, i). count_cond returns a one-argument function that takes +in n, which counts all the numbers from 1 to n that satisfy condition +when called.

+ +

Note: +When we say condition is a predicate function, we mean that it is +a function that will return True or False.

+ + + +
def sum_digits(y):
+    """Return the sum of the digits of non-negative integer y."""
+    total = 0
+    while y > 0:
+        total, y = total + y % 10, y // 10
+    return total
+
+def is_prime(n):
+    """Return whether positive integer n is prime."""
+    if n == 1:
+        return False
+    k = 2
+    while k < n:
+        if n % k == 0:
+            return False
+        k += 1
+    return True
+
+def count_cond(condition):
+    """Returns a function with one parameter N that counts all the numbers from
+    1 to N that satisfy the two-argument predicate function Condition, where
+    the first argument for Condition is N and the second argument is the
+    number from 1 to N.
+
+    >>> count_fives = count_cond(lambda n, i: sum_digits(n * i) == 5)
+    >>> count_fives(10)   # 50 (10 * 5)
+    1
+    >>> count_fives(50)   # 50 (50 * 1), 500 (50 * 10), 1400 (50 * 28), 2300 (50 * 46)
+    4
+
+    >>> is_i_prime = lambda n, i: is_prime(i) # need to pass 2-argument function into count_cond
+    >>> count_primes = count_cond(is_i_prime)
+    >>> count_primes(2)    # 2
+    1
+    >>> count_primes(3)    # 2, 3
+    2
+    >>> count_primes(4)    # 2, 3
+    2
+    >>> count_primes(5)    # 2, 3, 5
+    3
+    >>> count_primes(20)   # 2, 3, 5, 7, 11, 13, 17, 19
+    8
+    """
+
def counter(n): + i = 1 + count = 0 + while i <= n: + if condition(n, i): + count += 1 + i += 1 + return count + return counter
+ +
+ +
+ +

One question that might be nice to ask is: +in what ways is the logic for count_fives and count_primes similar, +and in what ways are they different?

+ +

The answer to the first question can tell us the logic that we want to +include in our count_cond function, while the answer to the second +question can tell us where in count_cond we want to be able to have +the difference in behavior observed between count_fives and +count_primes.

+ +

It'll be helpful to also keep in mind that we want count_cond to return +a function that, when an argument n is passed in, will behave similarly +to count_fives or count_primes. In other words, count_cond is a +higher order function that returns a function, that then contains the +logic common to both count_fives and count_primes.

+ +
+ +

Use Ok to test your code:

python3 ok -q count_cond
+ +
+ + +

Check Your Score Locally

+ +

You can locally check your score on each question of this assignment by running

+ +
python3 ok --score
+ +

This does NOT submit the assignment! When you are satisfied with your score, submit the assignment to Gradescope to receive credit for it.

+ + +

Submit Assignment

+ + +

Submit this assignment by uploading any files you've edited to the appropriate Gradescope assignment. Lab 00 has detailed instructions.

+ + +

Environment Diagram Practice

+ + +

There is no Gradescope submission for this component.

+ +

However, we still encourage you to do this problem on paper to develop +familiarity with Environment Diagrams, which might appear in an alternate +form on the exam. To check your work, you can try putting the code into PythonTutor.

+ + +

Optional Questions

+ + +

These questions are optional. If you don't complete them, you will +still receive credit for this assignment. They are great practice, so do them +anyway!

+ + +

Q4: Multiple

+ +

Write a function that takes in two numbers and returns the smallest number that +is a multiple of both. +

+ +
def multiple(a, b):
+    """Return the smallest number n that is a multiple of both a and b.
+
+    >>> multiple(3, 4)
+    12
+    >>> multiple(14, 21)
+    42
+    """
+
n = 1 + while True: + if n % a == 0 and n % b == 0: + return n + n += 1
+ + + +

Use Ok to test your code:

python3 ok -q multiple
+ +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hw/hw06/hw06.ok b/lab/sol-lab03/lab03.ok similarity index 55% rename from hw/hw06/hw06.ok rename to lab/sol-lab03/lab03.ok index 6c88d9378f..d746ebbf7c 100644 --- a/hw/hw06/hw06.ok +++ b/lab/sol-lab03/lab03.ok @@ -1,24 +1,25 @@ { - "name": "Homework 6", - "endpoint": "cal/cs61a/fa24/hw06", + "name": "Lab 3", + "endpoint": "cal/c88c/fa24/lab03", "src": [ - "hw06.py" + "lab03.py" ], "tests": { - "hw*.py": "doctest", + "lab*.py": "doctest", "tests/*.py": "ok_test" }, "default_tests": [ - "VendingMachine", - "midsem_survey" + "lambda", + "hof-wwpd", + "count_cond", + "composite_identity" ], "protocols": [ "restore", "file_contents", - "help", - "grading", "analytics", "unlock", + "grading", "backup" ] } \ No newline at end of file diff --git a/lab/sol-lab03/lab03.py b/lab/sol-lab03/lab03.py new file mode 100644 index 0000000000..055dcff175 --- /dev/null +++ b/lab/sol-lab03/lab03.py @@ -0,0 +1,91 @@ + +def composite_identity(f, g): + """ + Return a function with one parameter x that returns True if f(g(x)) is + equal to g(f(x)). You can assume the result of g(x) is a valid input for f + and vice versa. + + >>> add_one = lambda x: x + 1 # adds one to x + >>> square = lambda x: x**2 # squares x [returns x^2] + >>> b1 = composite_identity(square, add_one) + >>> b1(0) # (0 + 1) ** 2 == 0 ** 2 + 1 + True + >>> b1(4) # (4 + 1) ** 2 != 4 ** 2 + 1 + False + """ + return lambda x: f(g(x)) == g(f(x)) + + # Alternate solution: + def h(x): + return f(g(x)) == g(f(x)) + return h + + +def sum_digits(y): + """Return the sum of the digits of non-negative integer y.""" + total = 0 + while y > 0: + total, y = total + y % 10, y // 10 + return total + +def is_prime(n): + """Return whether positive integer n is prime.""" + if n == 1: + return False + k = 2 + while k < n: + if n % k == 0: + return False + k += 1 + return True + +def count_cond(condition): + """Returns a function with one parameter N that counts all the numbers from + 1 to N that satisfy the two-argument predicate function Condition, where + the first argument for Condition is N and the second argument is the + number from 1 to N. + + >>> count_fives = count_cond(lambda n, i: sum_digits(n * i) == 5) + >>> count_fives(10) # 50 (10 * 5) + 1 + >>> count_fives(50) # 50 (50 * 1), 500 (50 * 10), 1400 (50 * 28), 2300 (50 * 46) + 4 + + >>> is_i_prime = lambda n, i: is_prime(i) # need to pass 2-argument function into count_cond + >>> count_primes = count_cond(is_i_prime) + >>> count_primes(2) # 2 + 1 + >>> count_primes(3) # 2, 3 + 2 + >>> count_primes(4) # 2, 3 + 2 + >>> count_primes(5) # 2, 3, 5 + 3 + >>> count_primes(20) # 2, 3, 5, 7, 11, 13, 17, 19 + 8 + """ + def counter(n): + i = 1 + count = 0 + while i <= n: + if condition(n, i): + count += 1 + i += 1 + return count + return counter + + +def multiple(a, b): + """Return the smallest number n that is a multiple of both a and b. + + >>> multiple(3, 4) + 12 + >>> multiple(14, 21) + 42 + """ + n = 1 + while True: + if n % a == 0 and n % b == 0: + return n + n += 1 + diff --git a/lab/sol-lab03/lab03.zip b/lab/sol-lab03/lab03.zip new file mode 100644 index 0000000000..d171f2c1fb Binary files /dev/null and b/lab/sol-lab03/lab03.zip differ diff --git a/hw/hw05/ok b/lab/sol-lab03/ok similarity index 98% rename from hw/hw05/ok rename to lab/sol-lab03/ok index 0d2fead7a3..88874ff1a5 100644 Binary files a/hw/hw05/ok and b/lab/sol-lab03/ok differ diff --git a/lab/sol-lab02/tests/hof-wwpd.py b/lab/sol-lab03/tests/hof-wwpd.py similarity index 100% rename from lab/sol-lab02/tests/hof-wwpd.py rename to lab/sol-lab03/tests/hof-wwpd.py diff --git a/lab/sol-lab02/tests/lambda.py b/lab/sol-lab03/tests/lambda.py similarity index 100% rename from lab/sol-lab02/tests/lambda.py rename to lab/sol-lab03/tests/lambda.py diff --git a/lecture/lec07/index.html b/lecture/lec07/index.html index 8a94c18782..dec23d7495 100644 --- a/lecture/lec07/index.html +++ b/lecture/lec07/index.html @@ -152,6 +152,8 @@

Lecture Playlist

Videos + Recording + Slides (1pp) 07.py diff --git a/lecture/lec09/index.html b/lecture/lec09/index.html index a1b4fb018c..89b8818112 100644 --- a/lecture/lec09/index.html +++ b/lecture/lec09/index.html @@ -152,6 +152,8 @@

Lecture Playlist

Videos + 09.py +
diff --git a/lecture/lec10/index.html b/lecture/lec10/index.html index 45242a01a3..fd3b7016e2 100644 --- a/lecture/lec10/index.html +++ b/lecture/lec10/index.html @@ -152,6 +152,8 @@

Lecture Playlist

Videos + 10.py +