curry and compose -- functional language constructs

Alex Martelli aleaxit at yahoo.com
Wed May 2 03:36:09 EDT 2001


"Nick Perkins" <nperkins7 at home.com> wrote in message
news:HoNH6.45055$HF.10107141 at news4.rdc1.on.home.com...
    [snip -- currying and composition examples on the Python Cookbook]
> Both are examples of functions which create and return new functions.
> ( technically, i suppose they are just classes with __call__ methods..
> ...but i am not sure what the difference is, ..i don't see much
difference )

"From the outside" (the "client-code" side), a callable class-instance
mostly differs from a typical functional-programming function object in
that its state is modifiable.  You CAN use sort-of-FP (e.g. in Scheme)
where "closures" modify their own state, but the "mainstream" of FP
relies on non modifiable objects.  All in all, I agree the difference
is not huge!


> I think these are really cool, but i have never seen anyone use
> curry or compose.  Why not?  Shouldn't everyone use these
> all the time?

Why?  Whatever gets the job done well, in the simplest way available,
is what everyone "should" use.  Certain special cases of currying
(bound-methods of objects, which 'curry' the first argument, in
particular) _are_ very handy and extensively used.  Other cases, I
guess, are just thought of as less handy, less simple, less immediate,
and thus are used more rarely.  The tools are there when you need
them, but there's no special pressure for them to be used.

Python is a multi-paradigm language, much like, say, C++.  You can
mix object-oriented programming, traditional (procedural) programming,
some amounts of functional programming, and other paradigms yet where
appropriate (relational databases, for example, promote their own way
of thinking about certain parts of your program -- although they're
rarely thought of as a 'paradigm', I think they deserve to be...).

O-O is pretty central (particularly since you generally end up using
it to emulate most general cases of other paradigms:-), but it need
not dominate your programs.  But surely such domination must, a
fortiori, not be expected for _other_ paradigms than O-O.


> Does anyone have any other neat Python solutions that provide
> 'functional-style' features? (aside from those built-in )

Sure!  http://sourceforge.net/projects/xoltar-toolkit/ includes
functional.py, which focuses on enabling FP style programming in
Python.  David Mertz' article on functional programming in Python,
http://gnosis.cx/publish/programming/charming_python_13.html, may
give other interesting pointers.

> Do Python programmers generally think in a 'more functional'
> way than, say, Java programmers?
>
> Do they think in a 'less functional' way than LISP programmers?

I think it's hard to generalize about such issues, because there
are SO many programmers of Python, Java, AND Lisp, with overlap,
and with widely different backgrounds.  Java may be said to offer
inferior support for the FP paradigm than Python, and surely than
Common Lisp, so even somebody who DOES have a strong FP background
may get used to thinking in OO terms when using Java.  In practice,
I notice in myself that I tend to structure things around OO-first
in Python, too, despite some knowledge of Haskell, because the lack
of easy access to "lazy" evaluation in Python, starkly opposed to
"lazy by default" in Haskell, and vice-versa the ease of altering
state in Python versus the "side-effects free" approach of Haskell,
just bias the quest for "the simplest thing that can possibly work"
in different directions.


> Is Python well positioned to be the happy medium between
> hard-to-understand functional languages, and more traditional languages?

I adore Python, but I'm not sure it's reasonable to tag FP
languages as "hard to understand".  If a beginner to programming
was keen to start on a statically (compile-time) typed language,
I think he or she could do MUCH worse than begin with Haskell,
in particular.  Python, like other multi-paradigm languages, IS
in some sense a cheerful clairvoyant ("happy medium":-) between
the paradigms it supports best, as opposed to languages that
focus more intensively on just one overriding paradigm; it does
have the advantage of being much simpler than most other multi
paradigm languages, such as C++ and Common Lisp.


> --side question: what exactly do *args and **kwargs do?
> -- ( i mean the asterisks )
> -- it seems like they do a sort of in-place expansion/contraction..
> -- i can't find any reference in the doc..
> --are these forms usable outside of function parameter lists?

See http://www.python.org/doc/current/ref/calls.html for use of
* and ** prefixes in function-calls, and, for their use in def,
http://www.python.org/doc/current/ref/function.html.  Of course,
these are from the Language Reference manual, meant for "language
lawyers", but the * and ** relevant excerpts are not too obscure.

Taking def first, when it's talking about formal parameters it says:

"""
A function call always assigns values to all parameters mentioned
in the parameter list, either from position arguments, from keyword
arguments, or from default values.
If the form ``*identifier'' is present, it is initialized to a tuple
receiving any excess positional parameters, defaulting to the empty
tuple. If the form ``**identifier'' is present, it is initialized
to a new dictionary receiving any excess keyword arguments, defaulting
to a new empty dictionary.
"""

So: if in our "def func(<arguments>)" statement we include a "*name"
formal argument in the <arguments> list, we're saying that 'func'
can take any arbitrary number of extra unnamed parameters.  Inside
the body of 'func' when it's called, 'name' will refer to a tuple
of such "extra unnamed parameters" -- an empty tuple if there were
no extra unnamed parameters, in particular.

Similarly, if we include a "**kwds", we're saying 'func' can take
any arbitrary set of extra NAMED parameters; inside its body, 'kwds'
will refer to a dictionary with the correspondences name->value for
such "extra named parameters" -- an empty dictionary if there were
no extra named parameters, in particular.


The use of *something and **somethingelse in function _calls_ can be
seen as the "dual" of their use in function _definitions_.  The caller
already has a sequence or mapping, and wants to pass the relevant
items as 'unnamed', resp. 'named', parameters to the function it's
calling.  *asequence allows that for the sequence/unnamed parameters
case, and **adictionary similarly allows it for the mapping/named
parameters case.


I'm not sure about how you'd want to generalize these concepts
outside of a function definition or call, but, at least for now,
there ARE no other uses in Python of prefix * and ** except in
function parameter lists, formal or actual.


Alex






More information about the Python-list mailing list