Functional Programming
Bengt Richter
bokr at oz.net
Mon Dec 30 10:39:18 EST 2002
On 29 Dec 2002 21:51:24 -0600, Mike Meyer <mwm at mired.org> wrote:
>"Martin v. Löwis" <martin at v.loewis.de> writes:
>
>> beno wrote:
>> > Does anyone know of good sources of info for programming using the
>> > principles of functional programming in Python? Or, to what
>> > languages is Haskell similar? Any other advice on the subject
>> > equally welcomed!
>> - Currying (creating a function from another function by passing some
>> arguments): This is not directly available in Python; you can often
>> emulate it with lambda expressions.
>
>You don't need lambdas, and you can even make the programmer API look
>the same. For example:
>
>>>> inc = curry(int.__add__, 1)
>>>> inc(3)
>4
>>>> inc(10)
>11
>
>The definition of curry is:
>
>class curry:
> def __init__(self, func, *fixed_args):
> self.func = func
> self.fixed_args = fixed_args
self.__name__ = '<curried %s>' % func.__name__
>
> def __call__(self, *variable_args):
> return apply(self.func, self.fixed_args + variable_args)
>
>This idiom is where my python enlightenment began.
>
That is a cool class. I added the line to give the result a name, so my timing harness
could show it in the comparison of:
curryinc = curry(int.__add__, 1)
and
fasterinc = int.__add__.__get__(1)
Which shows that (as I'm sure is no surprise to you, but might be worth mentioning) you pay
a pretty steep price in performance vs something close to optimum.
BTW, I'm not sure the fasterinc way of doing what I did is going to be an ongoing feature,
so I'm not recommending it. But it seems like nice enough a way to generate an efficient
function-arg pair that acts like a bound method but which isn't, so maybe either it should
be blessed or some sanctioned version should be available? I just used it because it's
something fast to compare with. The name shows up as __add__.
[ 7:21] C:\pywk\clp\curry>timefuns timecurry -c fasterinc -i 1 -c curryinc -i 1 -n 100000
timing oh: 0.000013 ratio
__add__: 0.000004 1.00
<curried __add__>: 0.000047 12.13
[ 7:22] C:\pywk\clp\curry>timefuns timecurry -c fasterinc -i 1 -c curryinc -i 1 -n 100000
timing oh: 0.000013 ratio
__add__: 0.000004 1.00
<curried __add__>: 0.000047 13.12
12 or 13 times slower is pretty heavy. Of course it's very general. But a function factory
version seems to be about twice as fast (warning not tested beyond here ;-), e.g.:
def curryfun(func, *fixed_args):
curriedname = 'curried_f_%s' % func.__name__
exec """\
def %s(*variable_args):
return func(*(fixed_args+variable_args))
""" % curriedname in vars()
return vars()[curriedname]
[ 7:30] C:\pywk\clp\curry>timefuns timecurry -c fasterinc -i 1 -c curryinc -i 1 -c curryinc_f
-i 1 -n 100000
timing oh: 0.000012 ratio
__add__: 0.000004 1.00
<curried __add__>: 0.000047 13.06
curried_f___add__: 0.000025 6.83
Don't know if Dr. Who is relevantly cooking in India ;-)
Regards,
Bengt Richter
More information about the Python-list
mailing list