On Thu, Sep 09, 2004 at 09:41:36AM +0200, Jan Nieuwenhuizen wrote:
> Lionel Elie Mamane writes:
>> write (lambda (x) (accumulate cons nil x)) . This
>> non-curryfication is IMHO one of the most irritating "features" of
>> Lispy languages.
> I'm not familiar with caml like languages, could you explain what it
> is you find irritating?
Yeah, sure.
1) (One of) the point(s) in using functional languages (for me) is
that one can pass around functional values just as "normal"
values. Write higher-level functions, combinators, that abstract
powerful programming constructs and patterns and make them easy to
use, while typing few characters.
Joost has shown a few of these "classical" combinators in his
"scheme intro".
2) Brevity (taken reasonably) is a positive feature of a language.
The feature I'm talking about is the syntax that if f is a function
that takes n arguments, then (f a) is a function that takes (n-1)
arguments and behaves as
(lambda (x_0 ... x_{n-2}) (f a x_0 ... x_{n-2}))
. Mathematically, this makes use of the natural isomorphism between
A^(B*C) (the functions that take two arguments, the first in B, the
second in C, returning something in A) and (A^C)^B (the functions that
take an argument in B and return something in A^C, namely a function
that takes something in C and returns something in A).
Seen from this point of view (the "curryfied" point of view), writing
(lambda (x) (f a x)) is actually "just" an unnecessary complicated
equivalent of (f a). Just like (lambda (x) (f x)) is ... just f,
(lambda (x) (f a x)) is just (f a). (This is called eta-reduction, by
the way.)
Let's look at an example: let's suppose I want to increment every
element of the list l. Without curryfication, I have to write
something like
(map (lambda (x) (+ 1 x)) l)
with curryfication, I would write:
(map (+ 1) l)
which is much shorter and much more readable. Here you see that
actually, curryfication conflicts with a feature of Lispy languages:
variable number of arguments. The thing that lets you write (+), (+
1), (+ 1 2) or (+ 1 2 3 4) and these all have an (integer) value,
while in ML (+) is a function (of two arguments), (+ 1) is a function
of one argument, (+ 1 2) is an integer and (+ 1 2 3 4) is not
correct: It is the same as (3 3 4), i.e. using an integer as a
function.
Now, I want to increment every element of an element in a list of
lists:
(map (lambda (x) (map (lambda (x) (+ 1 x)) x)) l)
vs
(map (map (+ 1 x)) l)
For a list of lists of integers, compute the sums of the half of the
elements (where +3 is the function that takes three arguments and
returns their sum):
(map (lambda (x) (fold_left (lambda (x y) (+3 x y)) x)) l)
vs
(map (fold_left (+3 2) 0) l)
This "partial application" of functions to create new functions is
actually very common (at least, I tend to make use of it a lot). A lot
of "small" functions one wants are an already existing function, with
some of its arguments already chosen/bound.
Am I making sense now?
<<inline: signature.asc>>