469,342 Members | 6,455 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,342 developers. It's quick & easy.

Python syntax in Lisp and Scheme

I think everyone who used Python will agree that its syntax is
the best thing going for it. It is very readable and easy
for everyone to learn. But, Python does not a have very good
macro capabilities, unfortunately. I'd like to know if it may
be possible to add a powerful macro system to Python, while
keeping its amazing syntax, and if it could be possible to
add Pythonistic syntax to Lisp or Scheme, while keeping all
of the functionality and convenience. If the answer is yes,
would many Python programmers switch to Lisp or Scheme if
they were offered identation-based syntax?
Jul 18 '05
699 28961
In article <bm***********@f1node01.rhrz.uni-bonn.de>,
Pascal Costanza <co******@web.de> writes:
...
I think that's the essential point here. The advantage of the names car
and cdr is that they _don't_ mean anything specific.


gdee, you should read early lisp history ;-). car and cdr ha[d|ve] a
very specific meaning

hs

--

ceterum censeo SCO esse delendam
Jul 18 '05 #601
In article <6m********************@comcast.com>,
"Terry Reedy" <tj*****@udel.edu> writes:
...
two = 2
three = 3
two + three
For float constants in a language (such as Fortran) with multiple
float types (of different precisions), naming as part of a declaration
of precision is (or at least has been) a standard practice in some
circles. It makes it easy to change the precision used throughout a
program.


this is a good practice when the literals are parameters that you want
to change occasionally. other reasons why you want to do that is that
typing certain constants (e.g. pi or e) is error prone, so writing
them down once and binding them to a (descriptive) name is preferrably
to having to type them repeatedly. but unless they play a parameter
role, binding short literals to name doesn't serve any purpose
[Mind you, Python's lambda is next to useless anyway]


It is quite useful for its designed purpose, which is to abbreviate
and place inline short one-use function definitions of the following
pattern: def _(*params): return <expression using params>.


the last version of python i used was 1.5.x, and then the absence of
closures made the anonymous functions pretty useless
...


hs

--

ceterum censeo SCO esse delendam
Jul 18 '05 #602
In article <ra************************************@netnews.at tbi.com>,
Raffael Cavallaro <ra**************@junk.mail.me.not.mac.com> writes:
In article <8y**********@comcast.net>, pr***********@comcast.net wrote:
(flet ((add-offset (x) (+ x offset)))
(map 'list #'add-offset some-list))
But flet is just lambda in drag. I mean real, named functions, with
defun. Then the code becomes:

(add-offset the-list)

instead of either of theversions you gave.


the version he gave has the advantage that it doesn't clutter up the
namespace of the environment. with

(map (lambda (x) (+ x offset)) the-list)

you have everything that is relevant in the immediate neighborhood of
the statement. with a separate defun you have to search the program
to see what the function does. i agree that for lengthy functions
defining it separately and just writing the name is preferrable.
...
I guess I'm arguing that the low level implementation details should not
be inlined by the programmer, but by the compiler. To my eye, anonymous
functions look like programmer inlining.


i would call this a misconception

hs

--

ceterum censeo SCO esse delendam
Jul 18 '05 #603
In article <q-********************@comcast.com>,
"Terry Reedy" <tj*****@udel.edu> writes:

<pr***********@comcast.net> wrote in message
news:8y**********@comcast.net...
I disagree. This:

(map 'list (lambda (x) (+ x offset)) some-list)

is clearer than this:

(flet ((add-offset (x) (+ x offset)))
(map 'list #'add-offset some-list))


I agree for this example (and for the Python equivalent). But if the
function definition is several lines, then I prefer to have it defined
first so that the map remains a mind-bite-sized chunk.


i agree with your evaluation of what is preferrablem but i think you
would be surprised how clear the amove construct can look when
properly indented (something a decent editor would do automatically)

hs

--

ceterum censeo SCO esse delendam
Jul 18 '05 #604
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote in message news:<pa****************************@knm.org.pl>.. .
On Mon, 13 Oct 2003 13:51:22 -0700, Kaz Kylheku wrote:
Secondly, it would be unoptimizeable. The result of evaluating a
lambda expression is an opaque function object. It can only be called.


This is not true. When the compiler sees the application of a lambda,
it can inline it and perform further optimizations, fusing together
its arguments, its body and its context.


Kindly keep in mind the overall context of the discussion, which is
HOF's versus macros. The closures being discussed are ones passed down
into functions. Those closures typically cannot be inlined, except
under very special circumstances taken advantage of by a compiler with
very smart global optimizations.
Jul 18 '05 #605
In article <m2************@mycroft.actrix.gen.nz>,
Paul Foley <se*@below.invalid> wrote:
On Tue, 14 Oct 2003 01:26:54 -0400, David Mertz wrote:

....
In point of fact, Python could completely eliminate the operator
'lambda', and remain exactly as useful for HOFs. Some Pythonistas seem
to want this, and it might well happen in Python3000. It makes no
difference... the alpha and omega of HOFs is that functions are first
class objects that can be passed and returned. Whether they happen to
have names is utterly irrelevant, anonymity is nothing special.


True enough. Naming things is a pain though. Imagine if you couldn't
use numbers without naming them: e.g., if instead of 2 + 3 you had to
do something like

two = 2
three = 3
two + three

Bleargh! It "makes no difference" in much the same way that using
assembler instead of Python "makes no difference" -- you can do the
same thing either one, but one way is enormously more painful.

[Mind you, Python's lambda is next to useless anyway]


Sure, Python is a procedural programming language with things
like "if" statements that don't play very well in the context
of a lambda body, and with a notion of identifiers, variables
and scope that doesn't favor some of the conveniences that
lambda writers enjoy in functional programming languages. So
lambda is doomed to suffer from some limitations, and this seems
to bug some people no end.

It isn't clear that there's a real problem here, though, as
opposed to an occasion for contributing to the hot air supply
on USENET. (Heavens, what possessed me to read any of this
thread!?) Even if you suppose that Python programmers have
the same need for lambdas as one would in an FPL, what little
value they have is clearly in just the kind of applications
that actually work in Python anyway. The last time this came
up in another newsgroup, I rewrote a sort of well known
snippet of Haskell (a state monad) with named functions in
place of the lamdbdas the way you always see it, and proposed
that it was easier to read that way, and if anyone came forward
to contradict me I don't recall it. I think there is some
perverse thriftiness in most of us that makes us want to economise
on a carriage return here a name there, until our code becomes
so distilled that it's too perfect - too hard to understand.
Python is not about this kind of perfection, in my opinion.

Donn Cave, do**@u.washington.edu
Jul 18 '05 #606
ka*@ashi.footprints.net (Kaz Kylheku) writes:
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote in message news:<pa****************************@knm.org.pl>.. .
On Mon, 13 Oct 2003 13:51:22 -0700, Kaz Kylheku wrote:
Secondly, it would be unoptimizeable. The result of evaluating a
lambda expression is an opaque function object. It can only be called.


This is not true. When the compiler sees the application of a lambda,
it can inline it and perform further optimizations, fusing together
its arguments, its body and its context.


Kindly keep in mind the overall context of the discussion, which is
HOF's versus macros. The closures being discussed are ones passed down
into functions. Those closures typically cannot be inlined, except
under very special circumstances taken advantage of by a compiler with
very smart global optimizations.


If a macro works in a particular situation, then any equivalent HOF
can be inlined there as well. Granted, not all compilers will
actually do so, but the possibility trivially exists. This does not
depend on "very smart" global optimizations.

Matthias
Jul 18 '05 #607
On Tue, 14 Oct 2003 17:03:46 +0200, Jacek Generowicz wrote:
However, please _do_ tell me if you hear of anyone implementing Python
in Lisp[*].

Having Python as a front-end to Lisp[*] (as it is now a front-end to
C, C++ and Java) would be very interesting indeed.

[*] Common Lisp please.


You could always port Spy to CL (mentioned elsewhere in the thread).

- DS
Jul 18 '05 #608
Paul Foley <se*@below.invalid> wrote previously:
|True enough. Naming things is a pain though. Imagine if you couldn't
|use numbers without naming them:

This is plain idiotic. Someone else posted it equally disingenuously
too, FWIW.

Numbers aren't functions. Just because you can take a noun from a
sentence, and insert a different noun that changes the truth value is
REALLY not interesting. Let's try it:

Imagine you couldn't use MACROS without naming them
Imagine you couldn't use MODULES without naming them
Imagine you couldn't use KEYWORDS without naming them
...

If you want to suggest some ACTUAL advantage to HOFs, fine. Do it. But
please no annoying non-analogies.

In any case, I started my little splinter only in response to someone
who claimed that you needed lambdas to use HOFs. An obviously wrong,
and annoyingly stupid, claim. Pointing out that Haskell or Python could
easily drop lambda, with no detriment, simply makes that point.

Yours, David...

--
---[ to our friends at TLAs (spread the word) ]--------------------------
Echelon North Korea Nazi cracking spy smuggle Columbia fissionable Stego
White Water strategic Clinton Delta Force militia TEMPEST Libya Mossad
---[ Postmodern Enterprises <me***@gnosis.cx> ]--------------------------
Jul 18 '05 #609
In article <do************************@nntp1.u.washington.edu >, Donn Cave wrote:

...to contradict me I don't recall it. I think there is some
perverse thriftiness in most of us that makes us want to economise
on a carriage return here a name there, until our code becomes
so distilled that it's too perfect - too hard to understand.
Python is not about this kind of perfection, in my opinion.


True, but there are other reasons for anonymity besides the conservation of
character count (heh). Sometimes, you just don't know if something needs to
be reusable. Maybe YAGNI. For me, I typically go through an exploratory
phase when writing a new module where I don't name a lot of things, don't
create a lot of objects, and just try to solve a problem. I find that the
ability to toss around "thunks" helps me find a solution through
experimentation. Once the code is solid, I lift anonymous functions and
extract methods and classes where access patterns dictate the ability to
reuse and eliminate redundancy. At this point, I actually see the solution,
so I don't have to anticipate what sort of structure I'm going to need.

This is just one manner of solving problems, of course. However, it happens
to work particularly well (for me) in new domains which I lack the
experience necessary to work out a good structure in advance. With every
named object in a program comes the implicit assumption that the object will
later need to be called for by name. This goes for functions, classes, and
temporary variables.

I'm not trying to jump into the fire here, but I just wanted to illustrate
how anonynimity might be about imperfection, too. After all, you can always
repent^H^H^H^Hfactor later. =)

Peace,
Dave

--
..:[ dave benjamin (ramenboy) -:- www.ramenfest.com -:- www.3dex.com ]:.
: d r i n k i n g l i f e o u t o f t h e c o n t a i n e r :
Jul 18 '05 #610

"Hartmann Schaffer" <hs@heaven.nirvananet> wrote in message
news:3f******@news.sentex.net...
In article <6m********************@comcast.com>,
"Terry Reedy" <tj*****@udel.edu> writes:
For float constants in a language (such as Fortran) with multiple
float types (of different precisions), naming as part of a declaration
of precision is (or at least has been) a standard practice in some
circles. It makes it easy to change the precision used throughout a program.
this is a good practice when the literals are parameters that you

want to change occasionally. other reasons why you want to do that is that typing certain constants (e.g. pi or e) is error prone, so writing
them down once and binding them to a (descriptive) name is preferrably to having to type them repeatedly. but unless they play a parameter
role, binding short literals to name doesn't serve any purpose


My last sentence above gives a purpose, which is *the* purpose which
lead the editors of Applied Statistics to 'strongly advise' (up to
1985 at least, don't know about today) algorithm authors to "denote
all REAL constants symbolically" (A. S. Algorithms, p. 30). I'm just
reporting, not advocating. This in not an issue for standard Python,
which only allows access to C doubles.
[Mind you, Python's lambda is next to useless anyway]


It is quite useful for its designed purpose, which is to abbreviate and place inline short one-use function definitions of the following pattern: def _(*params): return <expression using params>.


the last version of python i used was 1.5.x, and then the absence of
closures made the anonymous functions pretty useless


The default-parameter hack which substituted for closures made lambdas
then more awkward, but I believe they were mostly just as useful as
today as callbacks and as HOF args. In any case, closures were
introduced over two years ago in 2.1, and your original statement says
'is', not 'used to be some years ago'.

Terry J. Reedy
Jul 18 '05 #611
In <od********************************@4ax.com>, on 10/13/2003
at 06:03 PM, David C. Ullrich <ul*****@math.okstate.edu> said:
Well it certainly _can_ be formalized. (Have you any experience with
_axiomatic_ Euclidean geometry?


That's not the same thing as formalized. Such authors as Hilbert left
out steps that were formally necessary but would have obscured the
reader's understanding.

--
Shmuel (Seymour J.) Metz, SysProg and JOAT

Unsolicited bulk E-mail will be subject to legal action. I reserve
the right to publicly post or ridicule any abusive E-mail.

Reply to domain Patriot dot net user shmuel+news to contact me. Do
not reply to sp******@library.lspace.org

Jul 18 '05 #612
"Terry Reedy" <tj*****@udel.edu> writes:
<pr***********@comcast.net> wrote in message

Thank you for the clarification. The message for me is this: a
Python-aware editor should have an option to keep a pasted-in snippet
selected so that the indentation can be immediately adjusted by the
normal selected-block indent/dedent methods without having to
reselect.


emacs. Just press C-c> or C-c< right after pasting.

'as
Jul 18 '05 #613
In article <bm**********@terabinaries.xmission.com>,
Thant Tessman <th***@acm.org> wrote:
A programmer accustomed to the
functional style finds the need in non-FP languages to name every
function analogously awkward.


No one is talking about need, but about clarity of exposition.

It is perfectly possible to program functionally in lisp, as I'm sure
you know. It just makes code less readable to use _anonymous_ functions.
Code is no less functional when the functions are named.

A theme of this whole thread is the difference between writing _what_
something does, and _how_ it does it. The higher up the ladder of
abstraction we go, the more we want to express _what_ is being done. We
leave the _how_ defined elsewhere, to be consulted only as needed.

Anonymous functions force the _how_ to be interleaved with the _what_,
breaking up the clarity of the _what_. Named functions (and macros)
allow the high level abstractions to be expressed in terms of _what_ is
happening, without unnecessary reference to _how_.

Anonymous functions force the reader to deal with _how_ precisely
because there is no descriptive name that expresses _what_ the funtion
does. This is an inappropriate conflation of two distinct purposes, that
can and should be separated in source code.
Jul 18 '05 #614
On Tue, 14 Oct 2003 14:38:42 -0400, "Shmuel (Seymour J.) Metz"
<sp******@library.lspace.org.invalid> wrote:
In <od********************************@4ax.com>, on 10/13/2003
at 06:03 PM, David C. Ullrich <ul*****@math.okstate.edu> said:
Well it certainly _can_ be formalized. (Have you any experience with
_axiomatic_ Euclidean geometry?
That's not the same thing as formalized.


Of course it's not. But it seems to me that his skepticism regarding
whether that proof _can_ be formalized must in fact be skeptism
regarding whether it's possible to state all the necessary axioms
and deduce the theorem without any appeal to the way things
look.
Such authors as Hilbert left
out steps that were formally necessary but would have obscured the
reader's understanding.


************************

David C. Ullrich
Jul 18 '05 #615
In article <y8**********@ccs.neu.edu>, Joe Marshall <jr*@ccs.neu.edu>
wrote:
The problem with this is that you've essentially outlawed MAP.

(map 'list (make-adder offset) some-list)

The problem with this is that MAKE-ADDER is no less a lambda in drag,
and it isn't even local.


I think you misunderstand me. I haven't outlawed map. I've simply asked
that it be used in a _named_ function or macro that expresses _what_ is
being done, not _how_. For example:

(defgeneric add-offset (some-sequence some-offset))

(defmethod add-offset ((some-list list) some-offset)
(map 'list #'(lambda (x) (+ x some-offset)) some-list))

(defmethod add-offset ((some-vector vector) some-offset)
(map 'vector #'(lambda (x) (+ x some-offset)) some-vector))
And the client code looks like your example:

(add-offset my-list current-offset) or

(add-offset my-vector vector-offset) etc.

Also see my reply to Thant Tessman entitled "Express What, not How."
Jul 18 '05 #616
Matthias Blume <fi**@my.address.elsewhere> wrote in message news:<m1************@tti5.uchicago.edu>...
ka*@ashi.footprints.net (Kaz Kylheku) writes:
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote in message news:<pa****************************@knm.org.pl>.. .
On Mon, 13 Oct 2003 13:51:22 -0700, Kaz Kylheku wrote:

> Secondly, it would be unoptimizeable. The result of evaluating a
> lambda expression is an opaque function object. It can only be called.

This is not true. When the compiler sees the application of a lambda,
it can inline it and perform further optimizations, fusing together
its arguments, its body and its context.


Kindly keep in mind the overall context of the discussion, which is
HOF's versus macros. The closures being discussed are ones passed down
into functions. Those closures typically cannot be inlined, except
under very special circumstances taken advantage of by a compiler with
very smart global optimizations.


If a macro works in a particular situation, then any equivalent HOF
can be inlined there as well. Granted, not all compilers will
actually do so, but the possibility trivially exists. This does not
depend on "very smart" global optimizations.


That is a case of bringing all of the function into the present
context so it can be mixed with the closures manually created there.

A macro controls how much material is inlined and how much isn't.

A macro can have its own binary interface between the expanded
material and some material in a library that is associated with the
macro.

The macro decides what forms need to be made into a closure that is
passed to the library and which are not.

These considerations are important, because in the Lisp world,
programs are dynamically updated while they are running. There are
versioning issues, like keeping new versions of a macro's library
compatible with existing macro-expansions, which won't be re-expanded
and re-compiled when the new code is loaded into an existing
application.
Jul 18 '05 #617
On Tue, 14 Oct 2003 22:09:44 +0000, Raffael Cavallaro wrote:
A theme of this whole thread is the difference between writing _what_
something does, and _how_ it does it. The higher up the ladder of
abstraction we go, the more we want to express _what_ is being done. We
leave the _how_ defined elsewhere, to be consulted only as needed.


Sometimes a function is so simple that its body is more clear than any
name. A name is an extra level of indirection. You must follow it to be
100% sure what the function means, or to understand what does it really
mean that it does what it's named after. The code also gets longer - not
only more verbose but the structure of the code gets more complex with
more interdependent parts. When you have lots of short functions, it's
harder to find them. There are many names to invent for the writer and
many names to rememner for a reader. Function headers are administrative
stuff, it's harder to find real code among abstractions being introduced
and used.

Why do you insist on naming *functions*? You could equally well say that
every list should be named, so you would see its purpose rather than its
contents. Perhaps every number should be named, so you can see what it
represents rather than its value. You could say that each statement of
a compound statement should be moved to a separate function, so you can
see what it does by its name, not how it does it by its contents. It's
all equally absurd.

A program should balance named and unnamed objects. Both are useful,
there is a continuum between cases where one or the other is more clear
and it's subjective in border cases, but there is place for unnamed
functions - they are not that special. Most high level languages have
anonymous functions for a reason.

--
__("< Marcin Kowalczyk
\__/ qr****@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

Jul 18 '05 #618
"Terry Reedy" <tj*****@udel.edu> writes:
The default-parameter hack which substituted for closures made lambdas
then more awkward, but I believe they were mostly just as useful as
today as callbacks and as HOF args. In any case, closures were
introduced over two years ago in 2.1, and your original statement says
'is', not 'used to be some years ago'.


Isn't it true though that the lambda can only contain a single expression
and no statements? That seems to limit closures somewhat.
Jul 18 '05 #619


Marcin 'Qrczak' Kowalczyk wrote:

On Tue, 14 Oct 2003 22:09:44 +0000, Raffael Cavallaro wrote:
A theme of this whole thread is the difference between writing _what_
something does, and _how_ it does it. The higher up the ladder of
abstraction we go, the more we want to express _what_ is being done. We
leave the _how_ defined elsewhere, to be consulted only as needed.
Sometimes a function is so simple that its body is more clear than any
name. ... Function headers are administrative
stuff, it's harder to find real code among abstractions being introduced
and used.

Why do you insist on naming *functions*? ... It's
all equally absurd.


years and years ago, perchance, the same person who introduced me to
referential transparency also went to great lengths to acquaint me with the
benefits of internal define.

A program should balance named and unnamed objects. Both are useful,
there is a continuum between cases where one or the other is more clear
and it's subjective in border cases, but there is place for unnamed
functions - they are not that special. Most high level languages have
anonymous functions for a reason.


please post the longest lambda calculus definition which you would like to
point to as an exemplar of coding clarity - an exercise, publication,
production code, whatever. i'm just wondering if you're serious about all of this.

....
Jul 18 '05 #620
In article <m3************@jcooper02.sagepub.com>,
Jock Cooper <jo***@mail.com> wrote:
"Terry Reedy" <tj*****@udel.edu> writes:
The default-parameter hack which substituted for closures made lambdas
then more awkward, but I believe they were mostly just as useful as
today as callbacks and as HOF args. In any case, closures were
introduced over two years ago in 2.1, and your original statement says
'is', not 'used to be some years ago'.


Isn't it true though that the lambda can only contain a single expression
and no statements? That seems to limit closures somewhat.


It limits lambdas. It doesn't limit named functions. Unlike lisp, a
Python function definition can be nested within a function call, and the
inner function can access variables in the outer function's closure.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science
Jul 18 '05 #621
In article <ep****************************@news.service.uci.e du>,
David Eppstein <ep******@ics.uci.edu> wrote:
Isn't it true though that the lambda can only contain a single expression
and no statements? That seems to limit closures somewhat.


It limits lambdas. It doesn't limit named functions. Unlike lisp, a
Python function definition can be nested within a function call, and the
inner function can access variables in the outer function's closure.


To clarify, by "unlike lisp" I meant only that defun doesn't nest (at
least in the lisps I've programmed) -- of course you could use flet, or
bind a variable to a lambda, or whatever.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science
Jul 18 '05 #622
In article <pa****************************@knm.org.pl>,
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote:

Sometimes a function is so simple that its body is more clear than any
name. A name is an extra level of indirection. You must follow it to be
100% sure what the function means, or to understand what does it really
mean that it does what it's named after.
Your argument is based on the assumption that whenever people express
_what_ a function does, they do so badly, with an inappropriate name.

We should choose our mode of expression based on how things work when
used correctly, not based on what might happen when used foolishly. We
don't write novels based on how they might be misread by the
semi-litterate.

Anonymous functions add no clarity except to our understaning of
_implementation_, i.e., _how_ not _what_. Higher level abstractions
should express _what_. Implementation details should remain separate,
both for clarity of exposition, and for maintanence and change of
implementation.
The code also gets longer
No, it gets shorter, because you don't repeat your use of the same
abstraction over and over. You define it once, then reference it by name
everywhere you use it.
- not
only more verbose but the structure of the code gets more complex with
more interdependent parts.
No, there are _fewer_ interdependent parts, because the parts that
correspond to the anonymous function bodies are _completely gone_ from
the main exposition of what is happening. These formerly anonymous
function bodies are now elswhere, where they will only be consulted when
it is necessary to modify them.

You seem to take the view that client code can't trust the interfaces it
uses, that you have to see how things are implemented to make sure they
do what they represent to do.

This is a very counterproductive attitude. Code should provide high
level abstractions, and clients of this code should be able to tell what
it does just by looking at the interface, and maybe a line of
documentation. It shouldn't be necessary to understand the internals of
code one uses just to use it. And it certainly isn't necessary to
include the internals of code one uses where one is using it (i.e.,
anonymous functions). That's what named functions and macros are for.
Inlining should be done by compilers, not programmers.

Anonymous functions are a form of unnecessary information overload. If I
don't need to see how something works right here, in this particular
context, then don't put its implementation here. Just refer to it by
name.
When you have lots of short functions, it's
harder to find them. There are many names to invent for the writer and
many names to rememner for a reader.
Which is why names should be descriptive. Then, there's little to
remember. I don't need to remember what add-offset does, nor look up
it's definition, to understand its use in some client code. Anonymous
functions are sometimes used as a crutch by those who can't be bothered
to take the time to attend to the social and communicative aspects of
programming. Ditto for overly long function bodies. How to express
intent to human readers is just as important as getting the compiler to
do what you want. These same programmers seem enamored of
crack-smokingly short and cryptic identifier and function names, as if
typing 10 characters instead of 3 is the real bottleneck in modern
software development. (Don't these people know how to touch type?)
Function headers are administrative
stuff, it's harder to find real code among abstractions being introduced
and used.

Seemingly to you, the only "real code" is low level implementation. In
any non-trivial software, however, the "real code" is the interplay of
high level abstractions. At each level, we craft a _what_ from some less
abstract _how_, and the _what_ we have just defined, is, in turn used as
part of the _how_ for an even higher level of abstraction or
functionality.

Why do you insist on naming *functions*? You could equally well say that
every list should be named, so you would see its purpose rather than its
contents.
I think this concept is called variable bindings ;^)

Perhaps every number should be named, so you can see what it
represents rather than its value.
Actually, they are _already_ named. The numerals we use _are_ names, not
numbers themselves. I'm surprised you aren't advocating the use of
Church Numerals for all numerical calculation.
You could say that each statement of
a compound statement should be moved to a separate function, so you can
see what it does by its name, not how it does it by its contents. It's
all equally absurd.
In the Smalltalk community the rule of thumb is that if a method body
gets to be more than a few lines, you've failed to break it down into
smaller abstractions (i.e., methods).
A program should balance named and unnamed objects. Both are useful,
there is a continuum between cases where one or the other is more clear
and it's subjective in border cases, but there is place for unnamed
functions - they are not that special. Most high level languages have
anonymous functions for a reason.


Yes, but they should live inside the bodies of named functions. Not lie
exposed in the middle of higher level abstractions. Please also see my
reply to Joe Marshall/Prunesquallor a few posts up in this thread.
Jul 18 '05 #623
|> Isn't it true though that the lambda can only contain a single
|> expression and no statements? That seems to limit closures somewhat.

David Eppstein <ep******@ics.uci.edu> wrote previously:
|It limits lambdas. It doesn't limit named functions. Unlike lisp, a
|Python function definition can be nested within a function call, and the
|inner function can access variables in the outer function's closure.

I don't really know Lisp, so I could be wrong. But my understanding is
that CL has a 'let' special form that works fine within a function
definition. In particular, you should be able to define inner functions
by binding a name to a lambda, using 'let'.

So there's nothing really special about the fact that Python (or
Haskell, ML, etc) can nest function definition. Of course, Haskell's
'let' and 'where' are quite wonderful... even better, syntaxwise, than
Python's nested 'def's.

Yours, David...

P.S. On the prior poster's misunderstanding: Lambdas in Python are
actually completely general. There is nothing you cannot express using
a single expression, even side effects--it just gets ugly doing it.
Basically, just like in CL, a list or tuple is a single expression, and
it evaluates its elements in predictable left-to-right order... you can
work out the rest of the ugly details from that fact. Or you can look
at my articles on "FP in Python"--however, my intent in those is NOT to
enable obfuscated Python, but to point to actual useful techniques.
It's a fine line though.

--
---[ to our friends at TLAs (spread the word) ]--------------------------
Echelon North Korea Nazi cracking spy smuggle Columbia fissionable Stego
White Water strategic Clinton Delta Force militia TEMPEST Libya Mossad
---[ Postmodern Enterprises <me***@gnosis.cx> ]--------------------------
Jul 18 '05 #624


David Eppstein wrote:

In article <ep****************************@news.service.uci.e du>,
David Eppstein <ep******@ics.uci.edu> wrote:
Isn't it true though that the lambda can only contain a single expression
and no statements? That seems to limit closures somewhat.


It limits lambdas. It doesn't limit named functions. Unlike lisp, a
Python function definition can be nested within a function call, and the
inner function can access variables in the outer function's closure.


To clarify, by "unlike lisp" I meant only that defun doesn't nest (at
least in the lisps I've programmed) -- of course you could use flet, or
bind a variable to a lambda, or whatever.


? which lisps have you been using?

i do not observe the spec for defun
(http://www.lispworks.com/reference/H...dy/m_defun.htm)
to place any restrictions on its context. anscillary discussion introduces the
issue of compile-time side-effects, eg whether the definition of the function
is known to exist for the purpose of error-checking, but there are no
constraints apparent to this reader on where the form may appear.

to wit
? (defun function1 (a)
(defun function2 (b) (+ a b)))
FUNCTION1
? (function1 2)
FUNCTION2
? (function2 3)
5
? (function1 5)
FUNCTION2
? (function2 3)
8
? (defun function* (a list)
(apply #'+ (mapcar (defun function2 (b) (+ a b)) list)))
FUNCTION*
? (function* 1 '(1 2 3))
9
?

that is, both the invocation for side-effect and for the returned value appear
to have the intended effect. on the other hand, it's not clear why one would
want to do this, so perhaps you mean something else?

....
Jul 18 '05 #625

pr***********@comcast.net writes:
[...]
I thought that whitespace was significant to Python.

My computer does not display whitespace. I understand that most
computers do not. There are few fonts that have glyphs at the space
character.

Since having the correct amount of whitespace is *vital* to the
correct operation of a Python program, it seems that the task of
maintaining it is made that much more difficult because it is only
conspicuous by its absence.


:-)

That remembers me that when the languages had significant spaces, the
programming was done with forms, sheets of physical paper preprinted
with empty spaces:
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

and you could then fill the blanks and have the significant spaces and
columns nicely visualized.

I assume python editors now show this kind of form as a background
bitmap, don't they.

--
__Pascal_Bourguignon__
http://www.informatimago.com/
Do not adjust your mind, there is a fault in reality.
Jul 18 '05 #626
Pascal Bourguignon <sp**@thalassa.informatimago.com> writes:
pr***********@comcast.net writes:
[...]
I thought that whitespace was significant to Python.

My computer does not display whitespace. I understand that most
computers do not. There are few fonts that have glyphs at the space
character.

Since having the correct amount of whitespace is *vital* to the
correct operation of a Python program, it seems that the task of
maintaining it is made that much more difficult because it is only
conspicuous by its absence.


:-)

That remembers me that when the languages had significant spaces, the
programming was done with forms, sheets of physical paper preprinted
with empty spaces:
|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_ |_|_|_|_|_|_|_|_|_|_|
1 7 12

and you could then fill the blanks and have the significant spaces and
columns nicely visualized.

I assume python editors now show this kind of form as a background
bitmap, don't they.


The Lisp Machine had a visual Hollerith editor.
Jul 18 '05 #627
Raffael Cavallaro <ra**************@junk.mail.me.not.mac.com> once said:
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote:
Sometimes a function is so simple that its body is more clear than any
name. A name is an extra level of indirection. You must follow it to be
100% sure what the function means, or to understand what does it really
mean that it does what it's named after.
Your argument is based on the assumption that whenever people express
_what_ a function does, they do so badly, with an inappropriate name.

....Anonymous functions add no clarity except to our understaning of
_implementation_, i.e., _how_ not _what_. Higher level abstractions
should express _what_. Implementation details should remain separate,
both for clarity of exposition, and for maintanence and change of
implementation.
I am in total agreement with Marcin. What you (Raffael) say here
sounds simply like dogma, rather than practical advice for constructing
software.

As a short practical example of what I'm saying, consider code like

-- I am translating this from another language; apologies if I have
-- screwed up any of the Haskell details
nat :: Parser Int
nat = do {c <- digit; return charToInt c}
`chainl1` (return \x y -> 10*x+y)

The code here parses natural numbers; it does do by parsing individual
digit characters, translating the digit characters into the
corresponding integers, and then combining the digit-integers into the
overall number.

If I understand you correctly, you would insist I write something like

nat :: Parser Int
nat = do {c <- digit; return charToInt c}
`chainl1` combineDigits
where combineDigits = return \x y -> 10*x+y

In my opinion, the code here is worse than the original.
"combineDigits" (or whatever we might choose to name it) is a one-time
function. It is not going to be reused (it's local to "nat"; moving it
to a more-top-level scope would just cause more problems finding a good
name for it).

Introducing a name for this function does nothing more than clutter the
code. The name provides no extra understanding. Of course the
function is "combining digits"! If the programmer is using chainl1, he
already knows that

chainl1 :: Parser a -> Parser (a->a->a) -> Parser a
-- parses a series of items separated by left-associative operators
-- which are used to combine those items

and he can infer "combining digits" just by seeing the call to chainl1
and inspecting its left argument.

Anonymous functions are a form of unnecessary information overload. If I
don't need to see how something works right here, in this particular
context, then don't put its implementation here. Just refer to it by
name.


There are more functional abstractions than there are reasonable names.

Forcing programmers to name every abstraction they'll ever encounter is
tantamount to forcing them to memorizing a huge vocabulary of names for
these abstractions. Perhaps you can remember the precise meanings of
ten-thousand function names off the top of your head. I, on the other
hand, can probably recall only a hundred or so. Thus, I must write,
e.g.

zipWith (\x y -> (x+y,x-y)) list1 list2

rather than

zipWith makePairOfSumAndDifference list1 list2

By only naming the most reusable abstractions (and, ideally, selecting
a set which are mostly orthogonal to one another), we provide a "core
vocabulary" which captures the essential basis of the domain. Lambda
then takes us the rest of the way. In my opinion, a core vocabulary of
named functions plus lambda is better than a separate name for every
abstraction. In natural language, such a scheme would be considered
double-plus-un-good, but in programming, I think it lends itself to the
simplest and most precise specifications.
I agree with your one of your overall theses, which is that we should
focus on the "what" rather than the "how". Where our opinions diverge,
however, is that I think sometimes the best way to communicate an
abstraction is to show the "how" inline, rather than creating a new
name in an attempt to capture the "what".

--
Brian M. McNamara lo****@acm.org : I am a parsing fool!
** Reduce - Reuse - Recycle ** : (Where's my medication? ;) )
Jul 18 '05 #628
Raffael Cavallaro <ra**************@junk.mail.me.not.mac.com> wrote in article <ra************************************@netnews.at tbi.com> in comp.lang.functional:
In article <pa****************************@knm.org.pl>,
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote:
Why do you insist on naming *functions*? You could equally well say that
every list should be named, so you would see its purpose rather than its
contents.

I think this concept is called variable bindings ;^)


Yes, but what Marcin is talking about outlawing anonymous variables, so
for example you can't write

amount_due = sum(item_prices) * (1 + tax_rate)

in his hypothetical programming language down the slippery slope (or is
it up the slippery slope?), but must write

subtotal = sum(item_prices)
tax_multiplier = 1 + tax_rate
amount_due = subtotal * tax_multiplier

just as programmers did before FORTRAN.

I would go one step further and point out that even in the code above,
there are still unnamed things whose functionality is possibly unclear.
These things are source code locations to which computations return,
aka continuations. For instance, what is the purpose of executing this
code above? The purpose is not to go through a bunch of arithmetic
operations for fun, but to compute the amount due.

def compute_amount_due:
subtotal = sum(item_prices)
tax_multiplier = 1 + tax_rate
amount_due = subtotal * tax_multiplier

There, clearer already. But what is the purpose of having the subtotal?
It is to add the tax to get the amount due.

def compute_amount_due:
sum(item_prices, add_tax_for_amount_due)

def add_tax_for_amount_due(subtotal):
tax_multiplier = 1 + tax_rate
amount_due = subtotal * tax_multiplier

What is the purpose of computing the tax_multiplier? To multiply with
the subtotal in order to get the amount due. (I assume a Python-ish
syntax with partial function application (currying) here.)

def add_tax_for_amount_due(subtotal):
add(1, tax_rate, subtotal_and_tax_multiplier_to_amount_due(subtotal ))

def subtotal_and_tax_multiplier_to_amount_due(subtotal , tax_multiplier):
amount_due = subtotal * tax_multiplier

But what's the purpose of having the amount due at all? Maybe it is to
print a bill:

def subtotal_and_tax_multiplier_to_amount_due(subtotal , tax_multiplier):
multiply(subtotal, tax_multiplier, print_bill_with_amount_due)

def print_bill_with_amount_due(amount_due):
...
Perhaps every number should be named, so you can see what it
represents rather than its value.

Actually, they are _already_ named. The numerals we use _are_ names, not
numbers themselves. I'm surprised you aren't advocating the use of
Church Numerals for all numerical calculation.


Functions are _already_ named as well. The lambda expressions we use
_are_ names, not functions themselves.
You could say that each statement of
a compound statement should be moved to a separate function, so you can
see what it does by its name, not how it does it by its contents. It's
all equally absurd.


In the Smalltalk community the rule of thumb is that if a method body
gets to be more than a few lines, you've failed to break it down into
smaller abstractions (i.e., methods).


So perhaps we should have the programming language outlaw anonymous
functions that are more than 4 lines long...

--
Edit this signature at http://www.digitas.harvard.edu/cgi-bin/ken/sig
"The first rule of politics: The ballots don't make the vote. The count
makes the vote." -- Boss Tweed in Gangs of New York
Jul 18 '05 #629
One of the most compelling arguments for anonymous functions comes from
Smalltalk, where the 'if' statement is implemented as a higher order method.
The equivalent in Python would look something like this:

class true_class:
def if_true(self, fn): return fn()
def if_false(self, fn): pass

class false_class:
def if_true(self, fn): pass
def if_false(self, fn): return fn()

true = true_class()
false = false_class()

(x == 0).if_true(anonymous_code_block)

Sure, Python already has an 'if' statement. That does not mean that there
are no other control structures worth implementing as HOFs.

However, I think I can make an even stronger case for anonymous functions
from my own code, which is littered with lambda expressions such as 'lambda:
1', 'lambda: 0', and 'lambda: None'. Giving those mini functions individual
names would be an atrocity, and even a factory function that returns these
mini functions would only hurt readability.
--
Rainer Deyke - ra*****@eldwood.com - http://eldwood.com
Jul 18 '05 #630
james anderson wrote:
Marcin 'Qrczak' Kowalczyk wrote:
Most high level languages have anonymous functions for a reason.


i'm just wondering if you're serious about all of this.


I think Marcin is serious, and any Haskeller would agree I suspect.

A good example from Haskell would be the use of lambda abstractions
as the second argument of the monadic >>= operator. Supplying names
for all those abstractions would be really awkward and yield highly
unreadable code IMO.

For those that don't like all those lambdas, Haskell's imperative style
"do" expressions can be used instead, but only for monads. There are
still occassions where explicit lambda's are an easier and clearer
alternative than defining named functions.

Regards
--
Adrian Hey
Jul 18 '05 #631

"Pascal Bourguignon" <sp**@thalassa.informatimago.com> wrote in
message news:87************@thalassa.informatimago.com...

pr***********@comcast.net writes:
Since having the correct amount of whitespace is *vital* to the
correct operation of a Python program, it seems that the task of
maintaining it is made that much more difficult because it is only
conspicuous by its absence.
That remembers me that when the languages had significant spaces, the programming was done with forms, sheets of physical paper preprinted with empty spaces:

[further idiocy snipped]

I do believe that several Lispers have suggested that people should
give Lisp a fair trial before rejecting it on account of parentheses
or macros. The same goes, of course, for Python and significant
indents/dedents. For most people who try Python, freedom from
visually redundant fences is a feature. Those who find it a bother
after trying are welcome to chose another language.

What makes the comments above doubly absurd is that Lisp has as much
or more need for 'significant spaces' as Python. Compare (1,2,3)
versus (1 2 3). Having the "correct amount of whitespace is *vital*
to the correct operation of a" Lisp program as much as for any other.
Do Lispers therefore use forms? I suspect not ;-)

Terry J. Reedy
Jul 18 '05 #632
gt*****@prism.gatech.edu (Brian McNamara!) writes:
I agree with your one of your overall theses, which is that we should
focus on the "what" rather than the "how". Where our opinions diverge,
however, is that I think sometimes the best way to communicate an
abstraction is to show the "how" inline, rather than creating a new
name in an attempt to capture the "what".


There are also times when "what" and "how" are literally the same,
which is when the "what" is a very trivial task.

It is a very slippery slope to insist coding styles in the name of abstraction:
- every value must have a name
- every function or procedure must be christened
- everything must be put in a class or object (I call this OOP - object
obfuscation pomposity)
- every line of code must be commented

There is an adverse social effect (since social effect was mentioned)
whenever an abstraction mechanism like the above ones is doctrinized.
Programmers will begin devaluing the mechanism. If you insist on
comments, they start writing silly comments; if you insist on naming
things, they start giving silly names; and if you insist on classes,
well, they start putting everything into one single class and making
all members static and public. They start seeing the abstraction
mechanism as a bother and stop seeing its potential benefits.

It is when you allow some freedom of not using a mechanism that the
the mechanism becomes valuable. (The political parallel: some people
like to stay in their countries precisely because their laws permit
them to leave. Once you remove that freedom, people begin to smuggle
themselves out.)

Now no one is suggesting to make all functions anonymous, all code
unstructured, and all aspects uncommented. Nothing of that sort! In
practice we give names to all non-trivial functions. Someone asserted
that we should judge a mode of expression for what it does when put in
good use, not what it could do when abused. That person should not
argue against anonymous functions by noting all the gory details of
implementation it might expose in the wrong hands.

And now I would like to sidetrack a bit and give an unrelated example
of Brian's point that sometimes "what" without "how" is completely
unclear.

I have an abstract data type to present you. This exercise is to test
how well you understand the "what" presentation, so the names of the
operations will not give you a clue. They are meaningful names though
- meaningful to me, a Cantonese speaker. (Just to show you how
meaningless the whole notion of "meaningful names" is.) But I will
present you "what" it does without mentioning "how".

It is a functional (immutable) abstract data type, so most operations
take an existing instance as a parameter and return a new instance.
The name of the abstract data type is LiDui.

Hung : LiDui
MoYun : LiDui -> Bool
PaiDui: (LiDui,Object) -> LiDui
DuiTau: LiDui -> Object
LeiDui: LiDui -> LiDui

MoYun(Hung) is true.
For any LiDui d:
If MoYun(d) is true, we have LeiDui(PaiDui(d,o))=d and DuiTau(PaiDui(d,o))=o.
If MoYun(d) is false, we have LeiDui(PaiDui(d,o))=PaiDui(LeiDui(d),o).

That's it.

I have never seen any first-year CS class present this abstract data
type this way. All presentations either show a simple pseudocode
implementation, or appeal to a mental model derived from a real life
experience, which is still a kind of simple pseudocode implementation,
except it is in real life terms instead of CS terms.
Jul 18 '05 #633
Rainer Deyke wrote:
...
(x == 0).if_true(anonymous_code_block)

Sure, Python already has an 'if' statement. That does not mean that there
are no other control structures worth implementing as HOFs.
True: if we had good code block literals, they'd help. However, the
issue of having to name the code block (with a def) is perhaps not as
crucial as it appears -- as important (and not implicit in the code
block being a literal) is in what scope the code block gets and sets
variables. If an anonymous code block, like a lambda, is totally
equivalent to a named function (sets variable locally, gets them in
lexical scope), then being able to write the above rather than

def guarded(): anonymous_code_block
(x == 0).if_true(guarded)

is a somewhat minor. The problem is, what could I possibly write in the
code block in order to obtain the same effect as with:
if x == 0:
x = 23
y += 1
and that's an issue of scope, not one of naming or not naming the block.
(Mertz's proposal for a 'block' keyword addresses this, but by wanting
the block's scope to be that of the caller rather than that of the
definer, it of course solves none of the problems Smalltalks block solve).

However, I think I can make an even stronger case for anonymous functions
from my own code, which is littered with lambda expressions such as
'lambda:
1', 'lambda: 0', and 'lambda: None'. Giving those mini functions
individual names would be an atrocity, and even a factory function that
returns these mini functions would only hurt readability.


I disagree: I find nullary(1), nullary(0) and the like very readable.
"lambda: x" is IMHO much more of a problem -- again because of scope.
Alex

Jul 18 '05 #634
Albert Lai <tr****@vex.net> writes:
Hung : LiDui
MoYun : LiDui -> Bool
PaiDui: (LiDui,Object) -> LiDui
DuiTau: LiDui -> Object
LeiDui: LiDui -> LiDui

MoYun(Hung) is true.
For any LiDui d:
If MoYun(d) is true, we have LeiDui(PaiDui(d,o))=d and DuiTau(PaiDui(d,o))=o.
If MoYun(d) is false, we have LeiDui(PaiDui(d,o))=PaiDui(LeiDui(d),o).

That's it.


I knew I forgot something.

If MoYun(d) is false, we have LeiDui(PaiDui(d,o))=PaiDui(LeiDui(d),o)
and DuiTau(PaiDui(d,o))=DuiTau(d).

MoYun(PaiDui(d,o)) is false.
Jul 18 '05 #635
In article <4u************@vex.net>, Albert Lai <tr****@vex.net> wrote:
It is a functional (immutable) abstract data type, so most operations
take an existing instance as a parameter and return a new instance.
The name of the abstract data type is LiDui.

Hung : LiDui
MoYun : LiDui -> Bool
PaiDui: (LiDui,Object) -> LiDui
DuiTau: LiDui -> Object
LeiDui: LiDui -> LiDui

MoYun(Hung) is true.
For any LiDui d:
If MoYun(d) is true, we have LeiDui(PaiDui(d,o))=d and
DuiTau(PaiDui(d,o))=o.
If MoYun(d) is false, we have LeiDui(PaiDui(d,o))=PaiDui(LeiDui(d),o).

That's it.


You sure you don't need a little more? This seems to fit both stacks
(MoYun always = True) and queues (MoYun true only for Hung).

That's one trouble with axiomatic definitions -- it's hard to be sure
you've expressed all of the behavior you intend to specify.
Another is that they can be difficult to understand.

--
David Eppstein http://www.ics.uci.edu/~eppstein/
Univ. of California, Irvine, School of Information & Computer Science
Jul 18 '05 #636


Adrian Hey wrote:

james anderson wrote:
Marcin 'Qrczak' Kowalczyk wrote:
Most high level languages have anonymous functions for a reason.

i'm just wondering if you're serious about all of this.


I think Marcin is serious, and any Haskeller would agree I suspect.


i have no argument with the utility of lambda abstractions.
i am trying only to understand the implications of an argument which, at least
as stated, rather unequivocally deprecates bindings.
the position which was proposed in the forgoing post was rather extreme.
i enquired to see of m.kowalczyk might offer some practical examples from
which it might be possible to learn something.
A good example from Haskell would be the use of lambda abstractions
as the second argument of the monadic >>= operator. Supplying names
for all those abstractions would be really awkward and yield highly
unreadable code IMO.


yes, i am good friends with lambda abstractions. we get along well and respect
each other. i am, however, neither married to one, nor an initiate in a sect
which deems it a transgression to utter the name of another deity.

....
Jul 18 '05 #637
Paul Rubin <http://ph****@NOSPAM.invalid> writes:
Jacek Generowicz <ja**************@cern.ch> writes:
However, please _do_ tell me if you hear of anyone implementing Python
in Lisp[*].

Having Python as a front-end to Lisp[*] (as it is now a front-end to
C, C++ and Java) would be very interesting indeed.
That would not be simple to do, because of weird Python semantics.


Could you elaborate on how Python semantics are weird (any more weird
than, say, Common Lisp)? and on why making a Common Lisp
implementation of Python would be any less simple than making a C
or Java implementation of Python?
But doing a Python dialect (a little bit different from CPython) would
be worthwhile.


In what sense would it differ? (I would not insist that it conform to
the Python/C API :-)

Would it differ from CPython any more than Jython differs from
CPython?
Jul 18 '05 #638
"Rainer Deyke" <ra*****@eldwood.com> wrote previously:
|However, I think I can make an even stronger case for anonymous functions
|from my own code, which is littered with lambda expressions such as 'lambda:
|1', 'lambda: 0', and 'lambda: None'. Giving those mini functions individual
|names would be an atrocity

Let's say I created a module lambdas.py (and generalized your functions):

OneFunc = lambda *a,**kw: 1
ZeroFunc = lambda *a,**kw: 0
NoneFunc = lambda *a,**kw: None
...etc...

In my application, I might have:

from lambdas import *
...
widget(param1, param2, callback=isCond and myFunc or NoneFunc)

Where exactly does the atrocity arise?! If anything, it's slightly more
readable than Deyke's little lambdas (and a little more concise too).

Yours, Lulu...

--
Keeping medicines from the bloodstreams of the sick; food from the bellies
of the hungry; books from the hands of the uneducated; technology from the
underdeveloped; and putting advocates of freedom in prisons. Intellectual
property is to the 21st century what the slave trade was to the 16th.
Jul 18 '05 #639
"Terry Reedy" <tj*****@udel.edu> writes:
"Pascal Bourguignon" <sp**@thalassa.informatimago.com> wrote in
message news:87************@thalassa.informatimago.com...

pr***********@comcast.net writes:
> Since having the correct amount of whitespace is *vital* to the
> correct operation of a Python program, it seems that the task of
> maintaining it is made that much more difficult because it is only
> conspicuous by its absence.
That remembers me that when the languages had significant spaces,

the
programming was done with forms, sheets of physical paper

preprinted
with empty spaces:

[further idiocy snipped]

I do believe that several Lispers have suggested that people should
give Lisp a fair trial before rejecting it on account of parentheses
or macros. The same goes, of course, for Python and significant
indents/dedents. For most people who try Python, freedom from
visually redundant fences is a feature. Those who find it a bother
after trying are welcome to chose another language.

What makes the comments above doubly absurd is that Lisp has as much
or more need for 'significant spaces' as Python.


That is simply incorrect. It is a small matter to set the readtable
such that things like (+x3) are interpreted as (+ x 3). This would
make it much more difficult to use complicated variable names, but
that's the tradeoff.
Compare (1,2,3) versus (1 2 3). Having the "correct amount of
whitespace is *vital* to the correct operation of a" Lisp program as
much as for any other. Do Lispers therefore use forms? I suspect
not ;-)


There's a bit of a difference between the whitespace separating tokens
and the whitespace that delineates blocks. The former is a member
of the half-open interval (0, +inf), the latter is a singleton.
Jul 18 '05 #640


John Roth wrote:
"Greg Ewing (using news.cis.dfn.de)" <g2********@sneakemail.com> wrote in
message news:bm************@ID-169208.news.uni-berlin.de...
Dave Benjamin wrote:
In that case, why do we eschew code blocks, yet have no problem with the
implicit invocation of an iterator,
I don't think code blocks per se are regarded as a bad thing.
The problem is that so far nobody has come up with an entirely
satisfactory way of fitting them into the Python syntax as
expressions.

I know. I played around with the idea a bit after it came up a couple
of weeks ago, and identified a number of issues.

<<SNIP>>
So let's say I want to use a code block instead of
a lambda or a named function in a map:

foobar = map(def (x, y, z):
astatement
anotherstatement
list1, list2, list3)
<<SNIP>> A third item is that I don't really care if we use 'def'
or not. Borrowing the vertical bar from Ruby, the map
example becomes:

foobar = map(| x, y, z |
astatement
anotherstatement
list1, list2, list3)

I kind of like this better, except for one really unfortunate
issue: it's going to raise havoc with code coloring algorithms
for a while.

John Roth


Hmm,
How about just using the presence of (...):: as starting a code block?
A call to a function that might take two function args and something else:
foo = bar(func1, func2, nonfunc)
would become:
foo = bar( (a,b)::
astatement
somemorestatements
,(c,d,e)::
anotherstatement
yetmorestatements
,nonfunc)

I used the double colon after the closing bracket as the statements of
the enclosed statement block must be double indented w.r.t foo

I guess the indentation of the arguments of bar (not including the
statement blocks could have less restrictive indentation.
Just as you could write
foo = bar(
func1,
func2,
nonfunc)
the indentation rules would have to be that the statement block is
double indented on the line after ):: and the statement block ends on
the next line with LESS indentation (more indentation would be tart of
the statement block).

Pad.
Jul 18 '05 #641
On Wed, 15 Oct 2003 00:41:28 +0000, Raffael Cavallaro wrote:
Your argument is based on the assumption that whenever people express
_what_ a function does, they do so badly, with an inappropriate name.
Sometimes there is no name which is more clear than the definition.

A random example from OCaml source:
if List.exists (fun q -> q.pat_loc = p.pat_loc) ps2 then ...

Would you write it like this? Please fill the appropriate <name>:
let <name> q = q.pat_loc = p.pat_loc in
if List.exists <name> ps2 then ...

Note that the function must be written here because it uses p which is
local, unless p was moved to its parameters and partially applied here
(this technique works for OCaml because of curring, it won't work for Lisp
or Scheme).
The code also gets longer


No, it gets shorter, because you don't repeat your use of the same
abstraction over and over.


If it's used only once then the code is longer - see above.
When you have lots of short functions, it's harder to find them. There
are many names to invent for the writer and many names to rememner for
a reader.


Which is why names should be descriptive.


Great, many long names :-)
Why do you insist on naming *functions*? You could equally well say
that every list should be named, so you would see its purpose rather
than its contents.


I think this concept is called variable bindings ;^)


I don't say I don't use variables. I say I don't use variables for *every*
subexpression. And sure I do use named functions, but not every function
deserves to be named.
In the Smalltalk community the rule of thumb is that if a method body
gets to be more than a few lines, you've failed to break it down into
smaller abstractions (i.e., methods).
Hmm, Smalltalk blocks are anonymous functions. Do you reject Smalltalk
blocks too? :-)
Yes, but they should live inside the bodies of named functions. Not lie
exposed in the middle of higher level abstractions. Please also see my
reply to Joe Marshall/Prunesquallor a few posts up in this thread.


You contradict yourself. First you say that "any anonymous function syntax
is undesirable", and they you accept anonymous functions in the middle of
higher level abstractions.

--
__("< Marcin Kowalczyk
\__/ qr****@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/

Jul 18 '05 #642


"Brian McNamara!" wrote:

Raffael Cavallaro <ra**************@junk.mail.me.not.mac.com> once said:
Marcin 'Qrczak' Kowalczyk <qr****@knm.org.pl> wrote:
Sometimes a function is so simple that its body is more clear than any
name. A name is an extra level of indirection. You must follow it to be
100% sure what the function means, or to understand what does it really
mean that it does what it's named after.
Your argument is based on the assumption that whenever people express
_what_ a function does, they do so badly, with an inappropriate name.

...

If I understand you correctly, you would insist I write something like

nat :: Parser Int
nat = do {c <- digit; return charToInt c}
`chainl1` combineDigits
where combineDigits = return \x y -> 10*x+y


when i read r.cavallaro's note, i saw no proscriptions. upon rereading it i
observe a value judgement and several characterizations. perhaps the reader
somehow misinterpreted them as pre/proscriptions. pehaps if the term "force"
were replaced with "require" the b.mcnamara would agree that there is no
contraction between them and his post in reply.

....
By only naming the most reusable abstractions (and, ideally, selecting
a set which are mostly orthogonal to one another), we provide a "core
vocabulary" which captures the essential basis of the domain. Lambda
then takes us the rest of the way. In my opinion, a core vocabulary of
named functions plus lambda is better than a separate name for every
abstraction. In natural language, such a scheme would be considered
double-plus-un-good, but in programming, I think it lends itself to the
simplest and most precise specifications.
what is the utility in overstating cavallaro's argument, in order to set up a
straw argument which reaches a conclusion quite in keeping with the original?
perhaps, yes ther is some utility in reiterating that extreme
pre/proscriptions in either direction are counterproductive. but, that in no
way weakens his argument.

I agree with your one of your overall theses, which is that we should
focus on the "what" rather than the "how". Where our opinions diverge,
however, is that I think sometimes the best way to communicate an
abstraction is to show the "how" inline, rather than creating a new
name in an attempt to capture the "what".

Jul 18 '05 #643
gt*****@prism.gatech.edu (Brian McNamara!) wrote in message news:<bm**********@news-int2.gatech.edu>...

I am in total agreement with Marcin. What you (Raffael) say here
sounds simply like dogma, rather than practical advice for constructing
software.

As a short practical example of what I'm saying, consider code like
[snip]
If I understand you correctly,
It appears you don't.

[snip]

In my opinion, the code here is worse than the original.


I agree.

[big snip]

You're taking things to a huge extreme to prove your point. Obviously
Raffael, being a programmer himself isn't suggesting that each and
every calculation/operation be put in a named function. The best
benchmark, is, I guess, the programmer himself. When programming, if
you find some portion of code that /you/ feel won't be understand when
you're rereading it or, you took a chunk out of a function to debug it
and at that point had to give it a name as another function etc etc;
/then/ keep that portion aside as a named function. It reduces the
burden on the person reading the original function that has been
shortened and, _gives him the choice_ to read this other function that
has been abstracted in that code.

Cheers,
Vijay

All future commitments are optimistic.
Jul 18 '05 #644
On Thu, 16 Oct 2003 11:43:06 -0700, David Eppstein <ep******@ics.uci.edu> wrote:
For simple use of built-in libraries,
http://online.effbot.org/2003_08_01_archive.htm#troll
looks like a good test case.


Quick hack follows.

edi@bird:/tmp > cat troll.lisp
(asdf:oos 'asdf:load-op :aserve)
(asdf:oos 'asdf:load-op :cl-ppcre)

(defparameter *scanner*
(cl-ppcre:create-scanner
"<a href=\"AuthorThreads.asp[^\"]*\">([^<]+)</a></td>\\s*
<td align=\"center\">[^<]+</td>\\s*
<td align=\"center\">[^<]+</td>\\s*
<td align=\"center\">\\d+</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*
<td align=\"center\">\\d+</td>\\s*
<td align=\"center\">(\\d+)</td>\\s*"))

(defun troll-checker (name)
(let ((target
(net.aserve.client:do-http-request
(format nil "http://netscan.research.microsoft.com/Static/author/authorprofile.asp?searchfor=~A" name)
:protocol :http/1.0)))
(cl-ppcre:do-scans (match-start match-end reg-starts reg-ends *scanner* target)
(flet ((nth-group (n)
(subseq target (aref reg-starts n) (aref reg-ends n))))
(let* ((group (nth-group 0))
(posts (parse-integer (nth-group 1)))
(replies (parse-integer (nth-group 2)))
(threads-touched (parse-integer (nth-group 3)))
(reply-to-post-ratio (/ replies posts))
(threads-to-post-ratio (/ threads-touched posts)))
(unless (< posts 10)
(format t "~55A R~,2F T~,2F ~:[~;TROLL~:[?~;!~]~]~%"
(subseq group 0 (min 55 (length group)))
reply-to-post-ratio
threads-to-post-ratio
(and (> reply-to-post-ratio .8)
(< threads-to-post-ratio .4))
(< threads-to-post-ratio .2))))))))

(compile 'troll-checker)

edi@bird:/tmp > cmucl
; Loading #p"/home/edi/.cmucl-init".
CMU Common Lisp 18e, running on bird.agharta.de
With core: /usr/local/lib/cmucl/lib/lisp.core
Dumped on: Thu, 2003-04-03 15:47:12+02:00 on orion
Send questions and bug reports to your local CMUCL maintainer,
or see <http://www.cons.org/cmucl/support.html>.
Loaded subsystems:
Python 1.1, target Intel x86
CLOS 18e (based on PCL September 16 92 PCL (f))
* (load "troll")

; loading system definition from /usr/local/lisp/Registry/aserve.asd into
; #<The ASDF1017 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM ASERVE {4854AEF5}> as ASERVE
; loading system definition from /usr/local/lisp/Registry/acl-compat.asd into
; #<The ASDF1059 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM ACL-COMPAT {4869AD35}> as ACL-COMPAT
; loading system definition from /usr/local/lisp/Registry/htmlgen.asd into
; #<The ASDF1145 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM HTMLGEN {487E64C5}> as HTMLGEN
; loading system definition from /usr/local/lisp/Registry/cl-ppcre.asd into
; #<The ASDF1813 package, 0/9 internal, 0/9 external>
; registering #<SYSTEM #:CL-PPCRE {48F32835}> as CL-PPCRE
; Compiling LAMBDA (NAME):
; Compiling Top-Level Form:
T
* (troll-checker "ed*@agharta.de")
comp.lang.lisp R0.93 T0.63
NIL
* (troll-checker "ep******@ics.uci.edu")
rec.photo.digital R1.00 T0.76
rec.arts.sf.written R0.99 T0.57
comp.lang.python R0.98 T0.64
rec.photo.equipment.35mm R1.00 T0.73
sci.math R1.00 T0.77
rec.puzzles R1.00 T0.75
comp.theory R1.00 T0.56
comp.graphics.algorithms R1.00 T0.87
comp.sys.mac.apps R1.00 T0.69
NIL
* (troll-checker "sp**@thalassa.informatimago.com")
comp.lang.lisp R0.91 T0.44
fr.comp.os.unix R1.00 T0.70
es.comp.os.linux.programacion R1.00 T0.67
fr.comp.lang.lisp R1.00 T0.40 TROLL?
comp.unix.programmer R1.00 T0.92
sci.space.moderated R1.00 T0.43
gnu.emacs.help R0.95 T0.84
sci.space.policy R1.00 T0.33 TROLL?
alt.folklore.computers R1.00 T0.43
comp.lang.scheme R0.83 T0.58
fr.comp.os.mac-os.x R0.92 T0.83
NIL

Granted, Portable AllegroServe[1] and CL-PPCRE[2] aren't "built-in"
(but freely available, compatible with various CL compilers, and easy
to install) and Python might have a bit more syntactic sugar but it
wasn't _too_ hard to do that in Lisp.

Edi

[1] <http://portableaserve.sf.net/>
[2] <http://weitz.de/cl-ppcre/>
Jul 18 '05 #645
On Thu, 16 Oct 2003 19:06:00 GMT, Raffael Cavallaro
<ra**************@junk.mail.me.not.mac.com> wrote:
is to write clear code. The reason we see 300 line function bodies is
that many programmers resist expressing the solution in the language of
the problem domain, preferring instead to write in an idiom that they
already understand, the programming language.
Do you have any objective evidence to suggest that this is true?
What proprtion exactly is due to this? The reason I ask is that
most of the long functions I have seen have been products of the
algorithm being implemented. If an algorithm takes 300 lines to
express it should be expressed as 300 lines. I have *never* seen
a long function that is the result of a programmer avoiding using
user vocabulary!

Equally I see no evidence whatsoever to suggest that users
express requirements in short chunks - usually the opposite, we
get presented with long complex prose describing a convoluted
business process and the programmer has to split that into its
natural chunks during analysis!

If anyone has done any research to connect long functions with
ignoring of user language I'm unaware of it and would be most
interested in seeing it.
The higher level abstractions of a complex piece of software will, of
necessity, be concepts in the problem domain.
Not necessarily(*), but I would agree that usually they are, but
at the lower levels the solution space may bear no resemblance to
the problem domain at all!

(*) For example where the solution architecture is based on a
mathematical technique which would be impractical in a manual
business process but is entirely practical using computing power.
As a somewhat dated example - the processes used in computer
crytography for example being entirely different to those used in
manual cryptrography. There will be some concepts in common
but many will be entirely novel.
interactions _in_the_language_of_the_problem_domain_. These problem
domain names are the appropriate units of the language that the software
should be written in. Named functions and macros are the appropriate
labels for the programmer's software definitions of the concepts of the
problem domain, not anonymous functions.
In the general case I agree completely but a blanket statement
that it is always true is absurd. There are many cases when a
programmer is dealing with issues that simply don't arise in the
human scenario. Anonymous functions are often used in
scenarios where a name is meaningless. Even in business processes
it is not unusual to find processes with names like JDI(Just Do
It) or DWN (Do Whatever's Necessary) to deal with extraordinary
scenarios. (Although ironically these are rarely the ones which
require anonymous funtions in code!)
At some low level of abstraction, when building the functionality of the
...
implementation. These implementations will, where appropriate, use
anonymous functions.
Ah, we do agree at this level. So your point only applies to
"high level" functions. The issue then becomes one of deciding at
what point the solution and problem domains separate.
However, once we get above this lower level of abstraction, we will be
dealing with concepts from the problem domain, which _have_names_.
Usually, but not always. Or often highly generic names which are
best implemented using higher order programming techniques
involving anonymous names.
This stands in direct opposition to those who think that software should
seek to _avoid_ names whenever possible. I, on the other hand find this
simple equation is true:

Names = Clarity
Again, in general I agree. But if the name is f and it is only
used for as long as it takes to convey a single use function into
the argument list of another function then I find the naming to
be of little or no value.
Some posters here have replied that this is just "obvious," and true
independent of the issue of anonymous functions. But the two issues are
_of_necessity_ related, because you cannot have both names and anonymity.
I'm not sure I agree there. It happens in the real world all the
time. (Consider Internet Chat Rooms! Many users there desire
anonymity while using a name which may not be their identity.
Indeed they achieve anonynimty through their false identity!)
prolixity, or names = exra work. But disdaining this work of finding
appropriate, descriptive, names from the problem domain, is a recipe for
obfuscated code.
I agree that good names are a good thing and time should be spent
considering appropriate ones but...
Worse, it is a recipe for failed software projects.
Bad naming is rarely if ever the reason for failed projects. It
may contribute by slowing down testing or integration and thus
causing estimate failure (the most comon reason for failed
projects) but naming alone is not enough to cause a failure IMHO.
failure to find good names from the problem domain indicates a failure
to properly understand the problem domain in its own terms. Failure to
understand the problem domain in its own terms means that the program's
design is almost certainly fatally flawed.


Insofar as the problem domain is reflected in the solution space
I agree. Certainly a programmer who does not understand the
vocabulary of his end user is unlikely to create good solutions.

Naming is important where a name aids understanding. If a name is
just there as a marker it serves no purpose. I agree that this
rarely happens at a high level in the design but I think it
happens at a higher level that you suggest. Not often, but often
enough to prevent blanket assertions being made.

Alan G.

Author of the Learn to Program website
http://www.freenetpages.co.uk/hp/alan.gauld
Jul 18 '05 #646
Alexander Schmolck <a.********@gmx.net> wrote in message news:<yf*************@black132.ex.ac.uk>...
Did it occur to you that people maybe use python not so much because they are
retards but because it's vastly more effective than CL at the tasks they
currently need to perform?


People use Python most likely for these reasons:

- they read some articles about it in popular press
- it is relatively new
- it came with their Linux distribution

The second point is important. When something is new, there is a
ready-made explanation for not being popular. When the pointy haired
boss asks why isn't the whole world using Python for everything, you
just have to say ``It's too new, so only the smart, hip people who
have their ears to the ground are using it, but just wait a few
years.''

It's easy to add a positive adornment to the explanation which gives
rise to an expectation of success, and which in turn creates a
psychological pressure to adopt or else be left behind!

Soon, the language starts being mentioned on job advertisements as a
desireable skill, and the pressure starts to snowball. At this point,
hordes of immature programmers are paniced into learning it, just so
they can put it on their resumes and be able to say something about it
in interviews.

But these programmers resent being pressured into learning! They
resent the new programming language, even if they contribute to its
body of popularity.

This is why in ten, fifteen, maybe twenty years, when the popularity
bubble of that language has long burst, there will be hordes of
detractors who will have ready-made seemingly technical explanations
why that language is no longer popular.
Jul 18 '05 #647
In article <eg************@vipe.ii.uib.no>, ke********@ii.uib.no wrote:
So, do you agree or not that anonymous functions can improve clarity
in some cases?


Of course. However, those cases tend to be low level abstractions
precisely because were talking about _anonymous_ functions, not
functional abstractions in general. Their anonymity itself prevents them
from improving the clarity of high level abstractions.

In other words, the higher the level of abstraction, the more we are
talking in the language of the problem domain. The language of the
problem domain has a vocabulary with _names_ for entities and their
interactions. Anonymous functions, by definition _have_no_names_, so
they can't possibly be isomorphic with the language of the problem
domain. If an anonymous function _does_ accomplish something identical
to a named entity or interaction in the problem domain, then you should
give your anonymous function _that_name_ from the problem domain. Now,
of course, it is a named function or macro, not an anonymous function
anymore.

The language of the problem domain, and anonymous functions, are,
_of_necessity_, mutually exclusive, because the domain experts use
_names_, not anonymous functions, when they talk about their domain of
expertise.
Jul 18 '05 #648
In article <3f****************@news.blueyonder.co.uk>,
al********@btinternet.com (Alan Gauld) wrote:
In the general case I agree completely but a blanket statement
that it is always true is absurd. There are many cases when a
programmer is dealing with issues that simply don't arise in the
human scenario. Anonymous functions are often used in
scenarios where a name is meaningless.


And in those cases, anonymous functions are perfectly appropriate.

However, when dealing with the existing abstractions of the problem
domain, named functions and macros are superior. I contend that a great
deal more code should be dealing with the existing abstractions of the
problem domain than is currently the norm. (Part of this is premature
optimization - Programmers are reluctant to break code into smaller
named units for fear that the additional code and function calls will be
more computationally costly.) Remember that mathematics, string
manipulation, network protocols, etc., are all well understood problem
domains with _preexisting_named_abstractions_. These named abstractions
are what we should be thinking and programming in, not the primitives of
whatever language we happen to be using, nor even in anonymous
functional abstractions.

In addition, even if the programmer finds some novel way, only possible
in a machine implementation, to express a solution, our ability to think
clearly about that process is greatly aided by giving it a _name_. E.g.,
it is much easier to think about different sorting methods (bubble sort,
quicksort, etc.) by refering to them by name, than it is to have to look
at an implementation of them every time we wish to refer to them.

Naming is a fundamental step in building abstraction. Anonymous
functions, keep us trapped at the level of abstraction at which they are
defined. If we wish to reuse them, we must reiterate them, because we
can't simply refer to them by name. Why not simply name them, and use
the names? This is, after all, how people have been communicating
abstractions since the dawn of spoken language.
Jul 18 '05 #649
On Thu, 16 Oct 2003 05:01:44 -0400, me***@gnosis.cx (David Mertz) wrote:
|> But the underlying issue was the spurious claim that lambda forms
|> were somehow required for HOFs, which is totally bogus. Python
|> could get by with only 'def', Lisp with only 'defun', and Haskell
|> only '=' and 'where'... and all of them would be just as capable at
|> using combinatorial and other HOFs.

Jacek Generowicz <ja**************@cern.ch> wrote previously:
|Yes, but arguments such as these are the first step down the slippery
|slope to Turing Equivalence. For just about any feature in just about
|any language, you could argue that the langugage could get by without
|it ... and taking this to its logical conclusion, you end up with
|assembler.

There is no such slope. OF COURSE everything is *computable* in every
language. That's obvious and trivial. Well, so are lots of things, but
it's not the point I've made.

What I am talking about is HIGHER ORDER FUNCTIONS. I.e. things
(abstractions) that don't exist in assembly language or in Turing
machines. You don't need that abstraction to do any computation, but
obviously, HOFs have a certain utility and beauty.

And you DO NOT NEED lambdas for HOFs! Categorically so--it's not that
you can use only a subset of HOFs if you only have def/defun/=. A
language that doesn't have lambda, but treats functions as first class,
can express EVERY HOF that one that adds lambda can.
ISTM there could be ways that you need BOTH named and un-named functions.
I.e., a function NEEDS a name in order to call itself recursively
(unless you create some specialized syntax for a recursive call).

OTOH, if you evaluate a def in a namespace where you don't know what
all the names are, you have a collision risk when you choose a name.
An un-named function eliminates that risk.

I.e., even if the function-definition part is identical in syntax and
capability, ISTM the name-binding side effect could be an issue.
Practically, it is probably rare that you can't use a named function,
but really def is a convenience construct that does name binding after
doing (what would be) a full-fledged lambda thing IMO.

Why should the following kind of thing be arbitrarily restricted?
(currently for two reasons -- a name is useless here and def
is a statement, not allowed in this contex):
funlist = [ ... (lambda value:
... lambda:'My value is %s'%value
... # imagine freedom to have full suites here
... )(y) for y in range(5)
... ] for fun in funlist: print fun()

...
My value is 0
My value is 1
My value is 2
My value is 3
My value is 4

(Not that a bound method (aka callable object if bound method is __call__) might
not be as good or better in many cases, but that might lead to asking whether
you NEED to be able to define functions outside of classes ;-)

ISTM there are uses for lists (and dicts for that matter) of functions
where the def names would at best be ignored side effects. E.g., perhaps
key or macro-key-sequence bindings for an editor, or event bindings for a GUI, etc.

This point is quite neutral as to whether lambda forms are otherwise
worthwhile. It's just a basic fact that a bunch of posters oddly want
to deny.

ISTM you are focusing on the defined function to the exclusion of
the name-binding-as-side-effect, and saying you don't need lambdas
because def's can generate the same functions, but ISTM that's not the whole story ;-)

Regards,
Bengt Richter
Jul 18 '05 #650

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

220 posts views Thread by Brandon J. Van Every | last post: by
37 posts views Thread by michele.simionato | last post: by
267 posts views Thread by Xah Lee | last post: by
14 posts views Thread by Paddy3118 | last post: by
1 post views Thread by CARIGAR | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by suresh191 | last post: by
1 post views Thread by haryvincent176 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.