Using curried higher-order functions

While currying is simple to visualize using ordinary functions, the real value shows up when we apply currying to higher-order functions. In an ideal situation, the functools.reduce() function would be curryable so that we would be able to do this:

sum = reduce(operator.add)
prod = reduce(operator.mul)

This doesn't work, however. The built-in reduce() function isn't curryable by using the PyMonad library, so the above examples don't actually work. If we define our own reduce() function, however, we can then curry it as shown previously.

Here's an example of a home-brewed reduce() function that can be used as shown earlier:

from collections.abc import Sequence
from pymonad import curry

@curry def myreduce(function, iterable_or_sequence): if isinstance(iterable_or_sequence, Sequence): iterator= iter(iterable_or_sequence) else: iterator= iterable_or_sequence s = next(iterator) for v in iterator: s = function(s,v) return s

The myreduce() function will behave like the built-in reduce() function. The myreduce() function works with an iterable or a sequence object. Given a sequence, we'll create an iterator; given an iterable object, we'll simply use it. We initialize the result with the first item in the iterator. We apply the function to the ongoing sum (or product) and each subsequent item.

It's also possible to wrap the built-in reduce() function to create a curryable version. That's only two lines of code; an exercise left for the reader.

Since the myreduce() function is a curried function, we can now use it to create functions based on our higher-order function, myreduce():

>>> from operator import add
>>> sum = myreduce(add)
>>> sum([1,2,3])
6
>>> max = myreduce(lambda x,y: x if x > y else y)
>>> max([2,5,3])
5  

We defined our own version of the sum() function using the curried reduce applied to the add operator. We also defined our own version of the default max() function using a lambda object that picks the larger of two values.

We can't easily create the more general form of the max() function this way, because currying is focused on positional parameters. Trying to use the key= keyword parameter adds too much complexity to make the technique work toward our overall goals of succinct and expressive functional programs.

To create a more generalized version of the max() function, we need to step
outside the key= keyword parameter paradigm that functions such as max(),
min(), and sorted() rely on. We would have to accept the higher-order function as the first argument in the same way as filter(), map(), and reduce() functions do. We could also create our own library of more consistent higher-order curried functions. These functions would rely exclusively on positional parameters. The higher-order function would be provided first so that our own curried max(function, iterable) method would follow the pattern set by the map(), filter(), and functools.reduce() functions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset