Self-currying functions

Carl Banks imbosol at aerojockey.com
Sun Jun 1 10:02:52 CEST 2003


Scott David Daniels wrote:
> Dave Benjamin wrote:
> 
>> In article <3ecff6e8$1 at nntp0.pdx.net>, Scott David Daniels wrote:
>>>Dave Benjamin wrote:
>>>>...
>>>>The following is my response, adapted from your example to support Alex
>>>>Martelli's curry function (and as a result, curried named parameters). I'm
>>>>starting to find interesting uses I hadn't anticipated.
>>>>...
>>>
>>>I am curious why you would want this ability (as opposed to curry..), 
> >> it seems there is a difference between a function with zero arguments
> >> and the result of that function....
>>>     Shouldn't selfcurry(lambda:1) == 1?
>> 
>> I'm not sure that I understand your comments. The point of selfcurry is to
>> modify the behavior of an existing function of two or more arguments so that
>> they do not need to be supplied at once. A function of zero or one arguments
>> does not need to be curried. Maybe selfcurry should just give you back your
>> function, unmodified, in that case.
> 
> OK, I really am asking a question rahter than trying to score debate
> points.  What I am curious about is why the selfcurry interface is
> preferable to the curry interface.  As an invention, I can see either
> one showing up first, but your response to Carl Baks' implementation
> of selfcurry is not, "Oh, curry is what I probably want."

I'm sorry, but you're not making much sense here, and it's starting to
get on my nerves.

I don't understand why you think currying and self-currying are
essentially the same thing.  I mean, you can accomplish similar things
with them, but self-currying does it in a different way, which is
often convenient.

With a self-currying function, you can do this:

    map(f, [list_of_self_curried_functions])

instead of this:

    map(lambda x:curry(f,x), [list_of_self_curried_functions])

Don't you think that could be useful, especially if you have a lot of
currying to do?

The self-curry thing was inspired by Haskell, as was revealed in the
original post.  If currying was explicit in Haskell, then you would
see that, like, a third of the program would be curry operators.


>> I don't see what this specific construct has to do with side effects,
>> besides the obvious connection with functional programming.
> 
> OK, my exposure to currying is from functional programming.  The only
> way I can see making a zero-argument function equivalent to its result
> is in an environment where you care about when a function is executed.

Another thing: where are you getting this idea?  It's not completely
obvious why you think self-currying makes a function equivalent to its
result--do you want to explain it?

Is it because a self-currying function "calls itself" when it has
enough arguments?  I don't see that as being equivalent to it's
result, except superficially.

When you call a self-currying function, I just see it just as a call,
nothing more.  It returns a result.  The result could be another
(distinct) self-currying function, or it could be something else.


> If functions are side-effect free, it doesn't matter when they are
> executed, and it may well be reasonable to consider a function of zero
> arguments as equivalent to its result.  In other environments, a
> programmer generally cares precisely when the function is elaborated.
> I hope this makes clear why I was talking about side-effect-free.

Yes, but most functional programmers are aware of this and avoid
writing and using functions with side effects.  You talk as if
side-effect-free code in a language like Python is a pipe dream and
can never really be obtained, but that's really not the case.

And this problem is not restricted to self-currying functions: it's a
problem for functional programming in general.  And only a minor one.


>>>I am curious why you prefer the selfcurry interface (even assuming
>>>keyword issues are dealt with).  It seems to to violate "explicit
>>>is better than implicit."
>> Can you elaborate on that? ...
> 
> This is the crux of my question, I suppose.  Forgive me for going
> there again, but if there are no side-effects, then functions are
> simply expression rewrites, and there is no meaningful difference
> between a function with zero arguments and its result.  If there
> are side-effects (such as I/O), when code is executed is crucially
> important, and seldom would you write "r = f(a)" without knowing
> whether a side-effect can be expected to happen.  I'd expect list
> comprehensions and map to be seen as bad style (too cute a trick)
> if side-effects are expected, for example.

Yet people use them often, without side effects.  Don't you think
people will do the same with self-currying functions?


> The expicit/implicit thing I'm talking about is the moment the
> function is elaborated (or called, or ...).  Selfcurry turns a
> function of an arbitrary number of arguments into a function of
> one argument returning a function of one argument returning ...
> a result.  It is the "magic" result point that I don't get.
> Curry of a function and some arguments returns a function of
> fewer arguments (or, for keyword args, potentially different
> defaults).  You still always know when the function is invoked
> to return a result, and your call will always expect either a
> further function or a result.

Two things.

First, I don't see how this follows from the side-effects issue.  It's
now clear to me that you have two different concerns, and you haven't
yet been able to verbalize any distinction between the two, and it's
confusing everyone.  Here they are:

1. That self-currying functions can have undesired effects on
   functions with side effects
2. That you don't know whether you are getting a function or a result
   when you call a self-currying function

I've addressed #1, already, and I think it's an insignificant problem.
In fact, now I can see how concern about #1 follows from #2.  But, to
be frank, you did a very poor job conveying this.


Second thing: I'll answer concern #2.

You see, there's "functional programming" and "eXtreme functional
programming."  (The latter is not to be confused with "Extreme
Programming(tm) that happens to be functional".)

"Functional programming" is using a map, reduce, and filter.  "eXtreme
functional programming" is where you pass around functions of
functions of functions of functions.  "eXtreme functional programming"
is where 90 percent (or whatever) of the data you pass around is
functions (which are often functions of functions).

I'm guessing you don't have much experience with "eXtreme functional
programming."  To be honest, I haven't either, but I understand the
mindset.

"eXtreme functional programmers" can rarely grasp the whole program,
even though they wrote it themselves.  They usually only understand
the program in pieces, by examining what one function at a time.  When
you program like that, you are very in-tune with what you're passing
in and what you're passing out.  You have to be.  In particular, you
have to know, when you pass a function to (for instance) map, that it
can be called with one argument; and you know what you're able to do
with the result.

Using selfcurry is not a problem for "eXtreme functional programmers."
If they selfcurry a function taking four arguments, they will use it
where a four-argument function is appropriate.

Do you think it's "magic" that self-currying function return "curries"
sometimes and "results" other times?  What's the difference?  The
result is probably itself a self-curring function, in "eXtreme
functional programming."

Basically, what I'm saying is, #2 is not a problem.  You know how many
arguments a self-currying function needs, and you use it accordingly.
You know you are going to add parameter now, and two to the result of
that, so you're sure to use a function that returns a "result" after
three arguments.


Sure, you could use regular currying for all of this, but do you
really want half the program to be curry calls?



>> I am not advocating that everybody write functions that curry their own
>> arguments, or that we throw away the ability to name positional parameters
>> when calling functions. I'd just like the ability to write functions that
>> have this behavior, and now I have it, and I'm pretty happy about it. =)
> 
> And I am not saying you shouldn't have the use of whatever floats your
> boat. I am truly eager to hear a use case for selfcurry over curry.  Is
> it simply brevity in intermediate expressions, or is there something I
> am missing.  Do you feel, "yes, of course, you know when a value is 
> produced and a final 'bowlegs' would be no big deal," or "the whole
> point is to be able to deal with this ambiguously?"
> 
> For those listening in, the parens at the end of "fun()" are what I
> mean by bowlegs.  I presume Dave knows the term.

I hope I've shed some light on it.


-- 
CARL BANKS




More information about the Python-list mailing list