We can use higher-order functions to convert a function that takes multiple arguments into a chain of functions that each take a single argument. More specifically, given a function f(x, y), we can define a function g such that g(x)(y) is equivalent to f(x, y). Here, g is a higher-order function that takes in a single argument x and returns another function that takes in a single argument y. This transformation is called currying.
    As an example, we can define a curried version of the pow function:

    1. >>> def curried_pow(x):
    2. def h(y):
    3. return pow(x, y)
    4. return h
    5. >>> curried_pow(2)(3)
    6. 8

    Some programming languages, such as Haskell, only allow functions that take a single argument, so the programmer must curry all multi-argument procedures. In more general languages such as Python, currying is useful when we require a function that takes in only a single argument. For example, the map pattern applies a single-argument function to a sequence of values. In later chapters, we will see more general examples of the map pattern, but for now, we can implement the pattern in a function:

    1. >>> def map_to_range(start, end, f):
    2. while start < end:
    3. print(f(start))
    4. start = start + 1

    We can use map_to_range and curried_pow to compute the first ten powers of two, rather than specifically writing a function to do so:

    1. >>> map_to_range(0, 10, curried_pow(2))
    2. 1
    3. 2
    4. 4
    5. 8
    6. 16
    7. 32
    8. 64
    9. 128
    10. 256
    11. 512

    We can similarly use the same two functions to compute powers of other numbers. Currying allows us to do so without writing a specific function for each number whose powers we wish to compute.
    In the above examples, we manually performed the currying transformation on the pow function to obtain curried_pow. Instead, we can define functions to automate currying, as well as the inverse uncurrying transformation:

    1. >>> def curry2(f):
    2. """Return a curried version of the given two-argument function."""
    3. def g(x):
    4. def h(y):
    5. return f(x, y)
    6. return h
    7. return g
    8. >>> def uncurry2(g):
    9. """Return a two-argument version of the given curried function."""
    10. def f(x, y):
    11. return g(x)(y)
    12. return f
    13. >>> pow_curried = curry2(pow)
    14. >>> pow_curried(2)(5)
    15. 32
    16. >>> map_to_range(0, 10, pow_curried(2))
    17. 1
    18. 2
    19. 4
    20. 8
    21. 16
    22. 32
    23. 64
    24. 128
    25. 256
    26. 512

    The curry2 function takes in a two-argument function f and returns a single-argument function g. When g is applied to an argument x, it returns a single-argument function h. When h is applied to y, it calls f(x, y). Thus, curry2(f)(x)(y) is equivalent to f(x, y). The uncurry2 function reverses the currying transformation, so that uncurry2(curry2(f)) is equivalent to f.

    1. >>> uncurry2(pow_curried)(2, 5)
    2. 32