functional.py 0.6 - Functional Programming in Python

Bryn Keller brk@jenkon.com
Thu, 12 Oct 2000 16:28:57 GMT


I'm pleased to announce the release of functional.py version 0.6,
released under the GNU LGPL.

functional.py can be obtained from:

http://sourceforge.net/projects/xoltar-toolkit/

functional.py provides support for a functional style of Python
programming.

It includes support for closures, curried functions, lazy expressions,
lazy tuples (functional programming languages call these lazy lists, but
since lists are mutable in Python, tuples are closer in meaning), and
lazy equivalents for map, filter, reduce, and zip. Also some higher
order functions for composing functions and such.

This release fixes  a problem that prevented zero length LazyTuples
(thanks to Alex Martelli for catching this one). It also adds several
new functions or functors:

class sequential:
    """
    Take a number of functions, and when called, call each of them in
turn. The
    first function in the list is the "main", or significant function,
and the
    others are taken for side effects only. Their return values do not
affect
    the return value of the also function, and any errors they raise are

    silently disregarded. If a function is explicitly specified via the
*main*
    parameter, that function will be the one whose return value is used,
regardless
    of where in the sequence it appears. Example:
    >>> def one():
    ...     print "one"
    ...     return 1
    ...
    >>> def two():
    ...     print "two"
    ...     return 2
    ...
    >>> def three():
    ...     print "three"
    ...     return 3
    ...
    >>> x = one()
    one
    >>> x
    1
    >>> x = sequential([one, two, three])()
    one
    two
    three
    >>> x
    1
    >>>
    >>> x = sequential([one, two, three], main = three)()
    one
    two
    three
    >>> x
    3
    >>>

    """


def also(*args):
    """
    Handles the common case for **sequential**, in which the first
function
    passed is the significant one. It takes free arguments instead of a
single
    sequence argument. Example:
    >>> def one():
    ...     print "one"
    ...     return 1
    ...
    >>> def two():
    ...     print "two"
    ...     return 2
    ...
    >>> def three():
    ...     print "three"
    ...     return 3
    ...
    >>> one()
    one
    1
    >>> x = one()
    one
    >>> x
    1
    >>> x = also(one, two, three)()
    one
    two
    three
    >>> x
    1
    >>> x = also(two, one, three)()
    two
    one
    three
    """

class always:
    """
    Returns a callable which always returns a given object.
    Example:
    >>> f = always(5)
    >>> f()
    5
    >>>
    """

class any_args:
    """
    Returns a callable which will take any arguments, and ignore them,
    calling *func* with no arguments. Useful with map(), or in the
common
    case of GUI event handlers which need to accept an event parameter,
    but do not use it. Example:

    >>> def return5():
    ...     return 5
    ...
    >>> return5("unneeded", "unnecessary")
    Traceback (innermost last):
      File "<stdin>", line 1, in ?
    TypeError: no arguments expected
    >>> f = any_args(return5)
    >>> f("unneeded", "unnecessary")
    5
    >>>
    """

class with_error:
    """
    Takes a function, and an error-handler function. When called, the
first
    function will be called. Any errors will cause the error function to

    be called with sys.exc_info() as the argument, *and the return value

    of the error handler will be returned.* If the error-handler
function
    re-raises the exception (or another), the exception will propagate
back
    to the caller. It is possible to chain error-handlers together with
    **atempt**, below.
    Example:
    >>> from operator import div
    >>> div(1/0)
    Traceback (innermost last):
      File "<stdin>", line 1, in ?
    ZeroDivisionError: integer division or modulo
    >>> def recover(exc):
    ...     return sys.maxint
    ...
    >>> safediv = with_error(div, recover)
    >>> safediv(1, 0)
    2147483647
    >>>
    """


class attempt:
    """
    Given a function sequence, attempt to call and return each in turn.
The
    return value of the first function to successfully return is
returned.
    This could be used to implement something like the pattern matching
techniques
    used in functional languages. A common use would be attaching error
handlers
    to functions after the fact. Suppose we want a want a version of the
div()
    function that returns sys.maxint when we attempt to divide by zero,
and
    zero if we attempt to divide by something other than a number as in
    this example:
    >>> def zeroHandler(exc_info):
    ...     exc = exc_info[1]
    ...     if isinstance(exc, ZeroDivisionError):
    ...             return sys.maxint
    ...     else:
    ...             raise
    ...
    >>> safediv = with_error(div, zeroHandler)
    >>> safediv(1, 0)
    2147483647
    >>> def typeHandler(exc_info):
    ...     exc = exc_info[1]
    ...     if isinstance(exc, TypeError):
    ...             return 0
    ...     else:
    ...             raise
    ...
    >>> safediv = with_error(div, attempt(zeroHandler, typeHandler))
    >>> safediv(1,0)
    2147483647
    >>> safediv(1, "abc")
    0
    >>>
    """


--
Bryn Keller
xoltar@starship.python.net