pointfree
is a small module that makes certain functional
programming constructs more convenient to use in Python.
Specifically, it provides:
- A decorator to enable automatic partial application of functions and methods.
- Notations for function composition through operator overloading.
- Helper functions to make composing generators more elegant.
The objective is to support the pointfree programming style in a lightweight and easy to use manner -- and in particular, to serve as a nice syntax for the kind of generator pipelines described in David Beazley's PyCon 2008 presentation, "Generator Tricks for Systems Programmers".
The pointfree
module is about using function composition notation
in conjunction with automatic partial application. Both of these features
are achieved by wrapping functions in the pointfree
class (which can also be applied as a decorator).
Several "pre-wrapped" helper functions are provided by the module. For
instance, if you wanted to define a function that returns the sum of
squares of the lengths of the strings in a list, you could do so by
combining the helpers pfmap
and
pfreduce
:
>>> from pointfree import * >>> from operator import add >>> fn = pfmap(len) >> pfmap(lambda n: n**2) >> pfreduce(add, initial=0) >>> fn(["foo", "barr", "bazzz"]) 50
Aside from the built-in helpers, you can define your own composable
functions by applying pointfree
as a decorator.
Building upon an example from Beazley's presentation, suppose you have
defined the following functions for operating on lines of text:
>>> import re >>> @pointfree ... def gen_grep(pat, lines): ... patc = re.compile(pat) ... for line in lines: ... if patc.search(line): ... yield line >>> @pointfree ... def gen_repeat(times, lines): ... for line in lines: ... for n in range(times): ... yield line >>> @pointfree ... def gen_upcase(lines): ... for line in lines: ... yield line.upper()
And you have some text too:
>>> bad_poetry = \ ... """roses are red ... violets are blue ... I like generators ... and this isn't a poem ... um let's see... ... oh yeah and daffodils are flowers too""".split("\n")
Now say you want to find just the lines of your text that contain the name of a flower and print them, twice, in upper case. (A common problem, I'm sure.) The given functions can be combined to do so as follows, using pointfree's automatic partial application and its function composition operators:
>>> f = gen_grep(r'(roses|violets|daffodils)') \ ... >> gen_upcase \ ... >> gen_repeat(2) \ ... >> pfprint_all >>> f(bad_poetry) ROSES ARE RED ROSES ARE RED VIOLETS ARE BLUE VIOLETS ARE BLUE OH YEAH AND DAFFODILS ARE FLOWERS TOO OH YEAH AND DAFFODILS ARE FLOWERS TOO
In addition to the >>
operator for "forward" composition (borrowed from
F#), functions can also be composed with the *
operator, which is
intended to be remniscent of the circle operator "∘" from algebra, or the
corresponding dot operator in Haskell:
>>> @pointfree ... def f(x): ... return x**2 >>> @pointfree ... def g(x): ... return x+1 >>> h = f * g >>> h(2) 9
Of course you don't have to define your methods using decorator notation in
order to use pointfree
; you can directly instantiate
the class from an existing function or method:
>>> (pf(lambda x: x*2) * pf(lambda x: x+1))(3) 8
(pf
is provided as a shorthand alias for the
pointfree
class.)
If you want automatic partial application but not the composition
operators, use the module's partial
decorator
instead:
>>> @partial ... def add_three(a, b, c): ... return a + b + c >>> add_three(1)(2)(3) 6
The module's partial application support has some subtle intentional differences from normal Python function application rules. Please see the module reference for details.
Full documentation is available on the web at:
http://pointfree.readthedocs.org/en/latest/
The easiest way to install the latest release on your machine is to get it from PyPI using pip:
$ pip install pointfree
or easy_install:
$ easy_install pointfree
Or you can download the module manually and perform the standard distutils incantations:
$ tar xzf pointfree-*.tar.gz $ cd pointfree-* $ python setup.py install
The module's development repository is hosted on Github:
https://github.com/markshroyer/pointfree
and the very latest development version can also be installed using pip:
$ pip install git+git://github.com/markshroyer/pointfree.git
pointfree
is compatible with the following Python
implementations:
- CPython 2.6, 2.7, 3.0, 3.1, 3.2, and 3.3
- PyPy 1.9.0
- IronPython 2.7.1
Python 3 is fully supported, including PEP 3102 keyword-only arguments.