For every line that is marked with a "# ?" symbol, try to determine what Python would print in the interactive interpreter. Then check to see if you got the answer right.

def square(x): return x*x def neg(f, x): return -f(x) # Q1 neg(square, 4) _______________ # Q2 def first(x): x += 8 def second(y): print('second') return x + y print('first') return second f = first(15) _______________ # Q3 f(16) _______________ # Q4 def foo(x): def bar(y): return x + y return bar boom = foo(23) boom(42) _______________ # Q5 foo(6)(7) _______________ # Q6 func = boom func is boom _______________ # Q7 func = foo(23) func is boom _______________ # Q8 def Troy(): abed = 0 while abed < 10: britta = lambda: abed abed += 1 annie = abed annie += 1 abed = 20 return britta jeff = Troy() shirley = lambda : jeff pierce = shirley() pierce() _______________

Define a function make_derivative that
returns a function: the derivative of a function f. Assuming that f is a
single-variable mathematical function, its derivative will also be a
single-variable function. When called with an int `a`

, the derivative will compute the
slope of f at the point `a`

.

The formula for finding the derivative of *f* at point *a* is

where *h* approaches 0. We will approximate the derivative
by setting *h* to a very small number: `0.00001`

.
The closer you make *h* to `0`

, the more accurate
the derivative approximation will be.

def make_derivative(f, h=1e-5): """Returns a function that is the derivative of f. >>> square = lambda x: x*x >>> derivative = make_derivative(square) >>> result = derivative(3) >>> round(result, 3) 6.0 """ "*** YOUR CODE HERE ***"

*Note:* make_derivative itself is not
the derivative; the function it *returns* is.

Now, we will visit the idea of helper functions. Sometimes, a
function must perform a lot of computations -- so many computations, in
fact, that it can get messy for the programmer to write. We can instead
define a *helper function* within the parent function that will
take care of some of the computations. The parent function then calls
the helper function as needed.

Recall that a quadratic function is a function of the form:

The *quadratic equation* is a classic algebraic formula used for
finding the roots of quadratic functions. Part of the quadratic equation
involves finding the *discriminant* (the part under the square root).

The quadratic equation is

where the discriminant, represented by the delta, is

Define a function find_root that,
given the coefficients `a`

, `b`

, and
`c`

of a quadratic function, will compute
a root of the function (normally, the quadratic equation has a
"+" or "-" sign -- we will focus on the "+" for now).

Your implementation should use a helper function called
discriminant, which also takes in the three
coefficients `a`

, `b`

, `c`

, and computes their discriminant. *Remember*,
find_root is not *returning*
the function discriminant; rather,
find_root will call
discriminant to help with some calculations.

from math import sqrt def find_root(a, b, c): """Returns one of two roots of a quadratic function. Since there are two roots to quadratics, return the the larger root. In other words, the + or - part of the quadratic equation should just be replaced with a + >>> find_root(1, 2, 1) -1.0 >>> find_root(1, -7, 12) 4.0 """ def discriminant(a, b, c): "*** YOUR CODE HERE ***" "*** YOUR CODE HERE ALSO ***"

Many procedures require a certain type of argument. For example, many arithmetic procedures only work if given numeric arguments. If given a non-number, an error results. For instance, pow('hello', 2) will result in the following error:

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

Suppose we want to write safe versions of procedures, that can check if the argument is okay, and either call the underlying procedure or return False for a bad argument instead of giving an error. (We'll restrict our attention to procedures that take a single argument.)

>>> sqrt('hello') Traceback (most recent call last): File "", line 1, in TypeError: a float is required >>> type_check(sqrt, isnumber, 'hello') False >>> type_check(sqrt, isnumber, 4) 2.0

1.) Write type_check. Its arguments are a
function, a type-checking predicate that returns True
if and only if the datum is a legal argument to the function, and the
datum.

For testing, you'll want the isnumber
procedure: use the one here (you don't have to understand how it works):

def isnumber(thing): try: int(thing) except: return False return True

2.) We really don’t want to have to use type_check explicitly every time. Instead, we’d like to be able to use a safe_sqrt procedure:

>>> safe_sqrt(’hello’) False >>> safe_sqrt(4) 2.0Don’t write safe_sqrt! Instead, write a procedure make_safe that you can use this way:

>>> safe_sqrt = make_safe(sqrt, isnumber)

It should take two arguments, a function (you can assume it takes exactly one argument) and a type-checking predicate, and return a new function that returns False if its argument doesn’t satisfy the predicate.Define a function cycle which takes in three functions as arguments: f1, f2, f3. cycle will then return another function. The returned fuction should take in an integer argument n and do the following:

- return a function that takes in an argument x and does the following:
- if n is 0, just return x
- if n is 1, apply the first function that is passed to cycle to x
- if n is 2, the first function passed to cycle is applied to x, and then the second function passed to cycle is applied to the result of that (i.e. f2(f1(x))). If n is 3, apply the first, then the second, then the third function (i.e. f3(f2(f1(x))))
- if n is 4, apply the first, then the second, then the third, then the first function (i.e. f1(f3(f2(f1(x)))))
- And so forth

Hint: most of the work goes inside the most nested function.

def cycle(f1, f2, f3): """ Returns a function that is itself a higher order function >>> add1 = lambda x: x+1 >>> times2 = lambda x: 2*x >>> add3 = lambda x: x+3 >>> my_cycle = cycle(add1, times2, add3) >>> identity = my_cycle(0) >>> identity(5) 5 >>> add_one_then_double = my_cycle(2) >>> add_one_then_double(1) # semanitcally the same as times2(add1(1)) 4 >>> do_all_functions = my_cycle(3) >>> do_all_functions(2) # semantically the same as add3(times2(add1(2))) 9 >>> do_more_than_a_cycle = my_cycle(4) >>> do_more_than_a_cycle(2) # semantically the same as add1(add3(times2(add1(2)))) 10 >>> do_two_cycles = my_cycle(6) # semantically the same as add3(times2(add1(add3(times2(add1(1)))))) >>> do_two_cycles(1) 19 """ " *** YOUR CODE HERE *** "

Fin.