Python syntax in Lisp and Scheme

H

Hartmann Schaffer

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
 
D

David Mertz

|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...
 
K

Kaz Kylheku

Marcin 'Qrczak' Kowalczyk said:
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.
 
D

Donn Cave

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, (e-mail address removed)
 
M

Matthias Blume

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
 
D

Daniel P. M. Silva

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
 
D

Dave Benjamin

...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
 
T

Terry Reedy

Hartmann Schaffer said:
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
 
S

Shmuel (Seymour J.) Metz

on 10/13/2003 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 (e-mail address removed)
 
A

Alexander Schmolck

Terry Reedy said:
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
 
P

Pascal Costanza

Hartmann said:
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[/QUOTE]

Yes, but noone (noone at all) refers to that meaning anymore. It's a
historical accident that doesn't really matter anymore when developing code.


Pascal
 
P

Pascal Costanza

Marcin said:
Because these hard-coded syntaxes are prettier than the extensible Lisp
syntax full of parentheses.

Obviously, you haven't tried to actually program in Lisp. Getting used
to the syntax is a matter of one or two weeks at most of actual coding,
provided you use a decent editor that supports parenthesis highlighting
and automatic indentation.

Despising Lisp because of its syntax is like thinking that Japanese is a
too complicated language because it doesn't use latin characters.


Mind you, I had more or less exactly the same objections to Lisp's
syntax about one and a half year ago. Now, I don't see any language out
there that nearly provides the same level of usability than Lisp,
exactly because of its regular syntax "full of parentheses". It's far
prettier and easier to read than languages whose syntaxes are based on
some unreflected, purely aesthetical choices.


Pascal
 
R

Raffael Cavallaro

Thant Tessman said:
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.
 
D

David C. Ullrich

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
 
R

Raffael Cavallaro

Joe Marshall <[email protected]> said:
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."
 
J

Jock Cooper

Terry Reedy said:
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.
 
K

Kaz Kylheku

Matthias Blume said:
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.
 
M

Marcin 'Qrczak' Kowalczyk

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.
 
J

james anderson

Marcin said:
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.

....
 
D

David Eppstein

Jock Cooper said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,169
Messages
2,570,920
Members
47,463
Latest member
FinleyMoye

Latest Threads

Top