# CS61A Lab 2

### Currying

We can transform multiple-argument functions into a chain of single-argument, higher order functions. For example, we can write a function `f(x, y)`

as a different function `g(x)(y)`

. This is known as **currying**.

For example, to convert the function `add(x, y)`

into its curried form:

1 | def curry_add(x): |

Calling `curry_add(1)`

returns a new function which only performs the addition once the returned function is called with the second addend.

1 | 1) add_one = curry_add( |

Refer to the textbook for more details about currying.

## 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: Lambda the Free

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

1 python3 ok -q lambda -u✂️As a reminder, the following two lines of code will not display anything in the Python interpreter when executed:

1

2 >>> x = None

>>> x

1 | >>> lambda x: x # A lambda expression with one parameter x |

### Q2: WWPD: Higher Order Functions

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

1 python3 ok -q hof-wwpd -u✂️

1 | >>> def even(f): |

## Parsons Problems

To work on these problems, open the Parsons editor:

1 | python3 parsons |

### Q3: A Hop, a Skip, and a Jump

Complete `hop`

, which implements a curried version of the function `f(x, y) = y`

.

1 | def hop(): |

### Q4: Digit Index Factory

Complete the function `digit_index_factory`

, which takes in two integers `k`

and `num`

as input and returns a function. The returned function takes no arguments, and outputs the offset between `k`

and the rightmost digit of `num`

. The *offset* between two numbers is defined to be the number of steps between the two numbers. For example, in `25`

, there is an offset of `1`

between `2`

and `5`

.

Note that `0`

is considered to have no digits (not even `0`

).

1 | def digit_index_factory(num, k): |

## Coding Practice

### Q5: Lambdas and Currying

Write a function `lambda_curry2`

that will curry any two argument function using lambdas.

**Your solution to this problem should fit entirely on the return line.** You can try first writing a solution without the restriction, and then rewriting it into one line after.

If the syntax check isn’t passing:Make sure you’ve removed the line containing`"***YOUR CODE HERE***"`

so that it doesn’t get treated as part of the function for the syntax check.

1 | def lambda_curry2(func): |

Use Ok to test your code:

1 | python3 ok -q lambda_curry2✂️ |

### Q6: Count van Count

Consider the following implementations of `count_factors`

and `count_primes`

:

1 | def count_factors(n): |

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.

1 | def count_cond(condition): |

Use Ok to test your code:

1 | python3 ok -q count_cond✂️ |

## Submit

Make sure to submit this assignment by running:

1 | python3 ok --submit |

# Optional Questions

### Q7: 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))`

. You can assume the output of `g(x)`

is a valid input for `f`

and vice versa. Try to use the `composer`

function defined below for more HOF practice.

1 | def composer(f, g): |

Use Ok to test your code:

1 | python3 ok -q composite_identity✂️ |

### Q8: I Heard You Liked Functions…

Define a function `cycle`

that takes in three functions `f1`

, `f2`

, `f3`

, as arguments. `cycle`

will return another function that should take in an integer argument `n`

and return another function. That final function should take in an argument `x`

and cycle through applying `f1`

, `f2`

, and `f3`

to `x`

, depending on what `n`

was. Here’s what the final function should do to `x`

for a few values of `n`

:

`n = 0`

, return`x`

`n = 1`

, apply`f1`

to`x`

, or return`f1(x)`

`n = 2`

, apply`f1`

to`x`

and then`f2`

to the result of that, or return`f2(f1(x))`

`n = 3`

, apply`f1`

to`x`

,`f2`

to the result of applying`f1`

, and then`f3`

to the result of applying`f2`

, or`f3(f2(f1(x)))`

`n = 4`

, start the cycle again applying`f1`

, then`f2`

, then`f3`

, then`f1`

again, or`f1(f3(f2(f1(x))))`

- And so forth.

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

1 | def cycle(f1, f2, f3): |

Use Ok to test your code:

1 | python3 ok -q cycle |