merits of Lisp vs Python

K

Ken Tilton

Paul said:
I don't really code in Lisp any more, I never felt a need for loop
when I was coding in Lisp, and I'm trying to move towards a style of
programming without loops (i.e. I'm playing with Haskell, which
doesn't have loops), giving me even less need for a hairy loop macro.

Oh, my. time to trot out my "hey, X is cool, let's use it for
everything!" rant.

Freud may not have said, "Sometimes a cigar is just a cigar.", but
sometimes (er, always) iteration is best handled with an iteration
construct. Any craftsman can tell you, use the right tool for the job.

the nice thing about Lisp's many paradigms is that the developer does
not become a slave to any paradigm. I think all-rules-all-the-time
Prolog is the poster boy for paradigm slavery. (I did try for a famous
two months to use Prolog as a general-purpose programming language.)

Just the sentence "I'm trying to program without loops" simply screams
"category error", if you think about it. Mind you, I had great fun using
a Logo which did not have iteration. Now I have fun with CL. They call
it a big ball of mud, but I do not thnk there is a tool in that chest I
have not used, just because that tool fit the problem best.

It only looks like a ball of mud if one does not right much code, and
that describes most Lispniks, so no wonder we ended up with Scheme.
Oops, wrong flamewar.

ken

--
Algebra: http://www.tilton-technology.com/LispNycAlgebra1.htm

"Well, I've wrestled with reality for thirty-five
years, Doctor, and I'm happy to state I finally
won out over it." -- Elwood P. Dowd

"I'll say I'm losing my grip, and it feels terrific."
-- Smiling husband to scowling wife, New Yorker cartoon
 
B

Bjoern Schliessmann

Robert said:
Because it's the language for which indentation is automatically
determinable. That is, one can copy/paste a chunk of code, hit a
key and suddenly everything is nicely indented.

Cool, so in other languages I need to set block marks like () and {}
and also indent the code for readability, and in Python I indent
only. From my POV that's less work.

Regards,


Björn

Xpost cll,clp
 
N

Neil Cerutti

Contrast the much more common

a = b[n]

with

(setf (aref a i) (aref b n))

and the attractions of Python may make more sense.


Here Python and Lisp are equal, 7 tokens vs 7 tokens, but in
Python one has to write less since "[]" are 2 chars while
"aref" are 4, plus the setf. But from counting the brain units
which I regard as an important factor they are both equal.


A comparison of brain units of the above snippets is irrelevant,
since the snippets are not equivalent.

The Python snippet will work for any object a that provides
__setitem__ and any object b that provides __getitem__.

I don't know what an equivalent Lisp snippet would be (or even
exactly how close the above snippet comes to matching the Python
code), but whatever it is would be a better foundation for
comparing brain units with the above Python.
 
P

Pascal Costanza

Paul said:
You're forgetting that CL tried to be more or less backwards
compatible with its predecessors, at least compatible enough that
large systems in Maclisp, Interlisp, Zetalisp, etc. could be ported
without too much pain. Therefore, CL could not erase too many
mistakes from the past. Scheme went somewhat further than CL at
cleaning things up, and Scheme's aficionados think CL is a clumsy old
kludge as a result. But it's still a Lisp dialect. The ML's, for
their part, were able to start from scratch.

It's funny: Language designers have been spending a lot of effort over
the decades on designing language constructs that help to improve the
opportunities to reuse of software libraries. Yet every five years, or
so, new languages and technologies come up that require everyone to
start from scratch. Starting from scratch is even being applauded, due
to some mythical belief that "this time, we are going to get it all right."

Something seems wrong here...


Pascal
 
B

Bruno Desthuilliers

Mathias Panzenboeck a écrit :
I do not know much about Lisp. What I know is:
Python is a imperative, object oriented dynamic language with duck typing,

Python is a dynamic multi-paradigm language which is mostly OO but has
support for procedural and functional programming
List
s/s/p/

is a declarative,
functional dynamic language -> those two languages have different scopes.

Lisp is a multi-paradigm language which is mostly functional but has
support for procedural and OO programming.

Both are highly dynamic. Neither are declarative.
 
B

Bruno Desthuilliers

Mathias Panzenboeck a écrit :
I currently visit a course about functional programming at the university of technology vienna:
python implements only a small subset of things needed to be called a functional language (list
comprehension).

Python has functions as first-class objects (you can pass functions as
arguments to functions, return functions from functions, and bind
functions to identifiers), and that's the only thing you need to use a
functional approach.
 
?

=?ISO-8859-1?Q?Andr=E9_Thieme?=

Bruno said:
Mathias Panzenboeck a écrit :

Python is a dynamic multi-paradigm language which is mostly OO but has
support for procedural and functional programming


Lisp is a multi-paradigm language which is mostly functional but has
support for procedural and OO programming.

Both are highly dynamic. Neither are declarative.

Well, Lisp does support some declarative features in the ansi standard.
Think about :before or :after methods. And with some days of work (has
already been done, so most Lispers could use it as a lib) you can get
many parts of Prolog. See http://bc.tech.coop/blog/040919.html


André
--
 
S

Slawomir Nowaczyk

On Tue, 12 Dec 2006 00:21:48 -0800

#> On Mon, 11 Dec 2006 23:24:07 -0500, Ken Tilton wrote:
#> > Also, Python does not support a functional style of programming so
#> > the line is the only meaningful textual entity. In this sense the
#> > primitiveness of Python makes editing easier.
#>
#> Why do you say that? Wouldn't a block in python be a "meaningful
#> textual entity" in the same way a lisp form would be?

No, it wouldn't, because that would make the argument false ;)

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

Monday is an awful way to spend 1/7th of your life.
 
S

Slawomir Nowaczyk

On Sat, 09 Dec 2006 10:08:01 +0000

#> Steven D'Aprano wrote:

#>> Anything any language can do is possible in any other language
#>
#> Not true. Concurrency, for example.

As in, say, not being able to implement concurrency in assembler?

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

"Be strict when sending and tolerant when receiving."
RFC 1958 - Architectural Principles of the Internet - section 3.9
 
S

Slawomir Nowaczyk

On Sat, 09 Dec 2006 14:57:08 -0500

#> In Python, I would need to do something like:
#>
#> control_code = connection.read_next_control_code()
#> if control_code == +break+:
#> connection.kill()
#> throw blah
#> else if control_code == +status+:
#> connection.send_status_summary()
#> else if control_code == +noop+ || control_code == +keep_alive+:
#> else:
#> error "CONTROL_CODE fell through conditional cascade; was not one of +BREAK+, +STATUS+, +NOOP+, +KEEP_ALIVE+"

Hardly.

I mean, well, possibly, *you* might need to, but others might just do
things like this:

def main():
connection = "+break+"
def kill():
print "kill",connection
raise "broken-by-client"
def status():
print "status"
def do_nothing():
pass
dispatch = {"+break+":kill,"+status+":status,"+noop+":do_nothing,"+keep-alive+":do_nothing}
dispatch[connection]()

When you compare the above with your lisp version

#> (let ((control-code (read-next-control-code connection)))
#> (ecase control-code
#> (+break+
#> (kill-connection connection)
#> (throw :broken-by-client))
#> (+status+
#> (send-status-summary connection))
#> ((+noop+ +keep-alive+))))
#> ;; +X+ indicates a constant

you may be able to see that they are pretty similar. Sure, Python does
not have fully functional lambda (which I, personally, consider to be a
drawback, but I understand that it is -- objectively -- a valid design
decision) so one needs to define functions for handling each case, but
there are some benefits to this approach as well.

#> To change what control codes you want to check for, you need to add
#> conditionals

Just as you need to add ecase branches...

#> for them and keep the error text relevant. The reality is that a
#> computer could be doing this for you, leaving your code simpler and
#> more easily changed.

Not really. If you care about the error message, you can use a subclass
of a dictionary instead and provide the correct behaviour when key is
not found.

#> Now someone will complain that the ECASE code means nothing until I
#> understand ECASE. Yep. But once you understand ECASE, you can look
#> at that code and, *at a glance*, see how control flows through it. In
#> the equivalent Python code, I need to walk through each conditional
#> and make sure they're all following the same pattern. If you're not
#> convinced, extend the example to 12 different control codes.

What you say is right, but only for bad Python code. Want to bet I can
write bad Lisp which will be just as unmaintainable?

PS. Good sigmonster, have a cookie!

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

Get the facts first - you can distort them later!
 
S

Slawomir Nowaczyk

On Tue, 12 Dec 2006 03:33:32 -0800

#> > > Also, Python does not support a functional style of programming so the
#> > > line is the only meaningful textual entity. In this sense the
#> > > primitiveness of Python makes editing easier.
#> >
#> > Why do you say that? Wouldn't a block in python be a "meaningful textual
#> > entity" in the same way a lisp form would be?
#>
#> You normally wouldn't refactor Python code by moving an indented block
#> to the inside of an expression. That is done all the time in Lisp.

You mean, you actually take something like else-form from an if and put
it inside, say, a multiplication? Sure, that is something you don't do
in Python often.

What you do in Python is take a block from one branch of "if" statement
and put it somewhere else (in a for loop, for example).

Sure, this requires you indent the block properly, although I am 100%
sure that I could teach emacs to adjust indentation automatically has I
needed to. I just never felt the need.

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

Programming: The art of debugging a blank sheet of paper
(or, in these days of on-line editing, the art of debugging an empty file).
 
K

Kaz Kylheku

I said:
To be a little provocative, I wonder if the idea that you're "talking to
the interpreter" doesn't apply more to lisp than to python; you can have
any syntax you like, as long as it looks like an AST.

Actually, that is false. You can have any syntax you like in Common
Lisp. For instance, the syntax of Python:

http://trac.common-lisp.net/clpython/

What thesaurus are you using which lists "provocative" as a synonym for
"uninformed"?
 
S

Slawomir Nowaczyk

On Tue, 12 Dec 2006 10:30:40 -0700

#> Imagine if one could write this in Python:
#>
#> defsyntax unless(condition, commands):
#> if not condition:
#> commands
#>
#> And use it like this:
#>
#> unless day == 'Sunday':
#> work()
#>
#> That'd be pretty cool, right?

Left... What is cool in this?

Sure, I love "unless" in Lisp, where it save me a whole one pair of
parentheses, but in Python both of those are equally readable

if not day == 'Sunday'
unless day == 'Sunday'

and the first one is standard, while the second is not.

#> As mentioned above, macros can make one's life significantly nicer.

Sure. I sometimes (when writing code) wish we had macros in Python. I do
know they can be useful. But then, when reading code, I am actually glad
we do not have them. Their benefits in a language like Python would
hardly pay off.

#> Wouldn't it be nice to have a macro with-open-file?
#>
#> filefor line in path:
#> foo(line)
#> bar(line)
#> baz(line)

Not really. *If* this code bothers you, just do

def with-open-file(path,fun):
file = open(path,"r")
for line in file:
fun(line)
file.close()

def handle-line(line):
foo(line)
bar(line)
baz(line)

with-open-file("path",handle-line)

Sure, it takes some time to get used to this, and at the beginning you
really miss full-blown lambda, but it does have its own benefits.

#> o Speed
#>
#> Lisp interpreters are several orders of magnitude faster than Python,
#> and Lisp compilers are faster yet. Speed's not the most important
#> thing, but it is _an_ important thing; all other things being equal,
#> the faster solution is better.

Sure. But in 20-30 years, Python might get there.

#> o Symbols
#>
#> In Lisp, a symbol is essentially a hashed string; two symbols are alike
#> if their names are alike, but comparison of symbols is a constant-time
#> operation. Thus where in Python I have lots of string comparisons for
#> constants, and in C I have #defined integers, in Lisp I have symbols.
#> It's not just a performance hack--symbols are part of why macros and
#> packages work--but when I miss them, I miss them for the performance
#> side of things

Well, you could fake symbols for most of the typical uses pretty
easily... It won't look as good as it does in Lisp, but it will solve
most problems.

OTOH, if dictionary of strings is too slow, than maybe you are not using
the right tool.

#> o CLOS
#>
#> The Common Lisp Object System is a really remarkable piece of work.
#> Among other things, it has generic functions instead of methods. E.g.
#> in Python or most other OO languages object.method(arg1, arg2) is
#> really just a fancy piece of syntactic sugar for method(object, arg1,
#> arg2); method does different things depending on the type of object,
#> its first argument.
#>
#> Wouldn't it be nice to be able to specialise a method on _any_ subset
#> of its arguments, not just its first one? Well, CLOS offers that.
#> (method object1 object2) could be specialised on the first argument,
#> the second or both. This can be very powerful.

There are modules for Python offering exactly that.

However, the Pythonic solution is not to rely on types too much anyway,
in the first place.

#> Wouldn't it be nice to specify that some action be taken before or
#> after a superclass's method, rather than over-riding that method
#> entirely? Sure, one can over-ride the method and then call it within
#> one's own code, but that obscures the meaning of what one's doing.

You can easily create a decorator which will do just that. I suppose you
could also create a metaclass which would do that, but it's too late for
me to be sure ;)

--
Best wishes,
Slawomir Nowaczyk
( (e-mail address removed) )

The nice thing about standards is that there are so
many of them to choose from.
 
G

George Sakkis

Bill said:
You're missing Ken's point, which is that in Lisp an s-expression
represents a single concept - I can cut out the second form of an IF
and know that I'm cutting the entire test-form. I don't have to
choose the correct "set of complete lines" to correctly move code
around.

Why is selecting a valid s-expression easier than selecting a python
block ? If you mistakenly select an extra parenthesis or omit one, it's
the same thing. Having said that, I find this problem is mostly
academic in both languages with modern editors... there are less
trivial excuses to keep the flamewar raging ;-)

George
 
P

Paul Rubin

jayessay said:
You're mistaken, I'm not forgetting this. And despite this being
true, CL added several "new" things that (again through actual
experience) were deemed sufficiently understood to add (CLOS,
conditions, and such).

I thought CL's condition system was similar to Maclisp or at least the
Lisp machine.
But, Scheme was before CL (and indeed CL took some things from
Scheme). Of course Scheme too has continued to evolve.

But Scheme was able to depart from earlier Lisps more than CL was,
because it made no attempt at backwards compatibility. For example,
its designers chose to make it a Lisp-1 (not saying that's better,
just incompatibly different). CL's designers did really not have that
choice.
Well, if you lower into "flamewar" talk, CL aficionados have similar
things to say about Scheme. But that is just irrelevant silly flamage.

I've never heard CL aficionados say that about Scheme. I've heard
them say that it's an elegant jewel that's too academic and
constricted for practical large program development, which is a
completely different criticism.
There are Lisps like this as well (EuLisp sort of and now Arc). But
really, how is "starting from scratch" really an advantage?

Starting from scratch means being able to make choices fundamentally
incompatible with the old language. Consider ML's type system--ML is
statically typed throughout and relies on type inference pervasively.
Yes you could make it look like Lisp by replacing the surface syntax
with parentheses, but it's really different under the skin. Again not
necessarily better, but made choices unavailable to someone trying to
incrementally evolve some Lisp dialect.
Especially from a _practical_ point of view.

Topic started with how new ideas enter a language. Practicality is
not of so much concern.
Admittedly, I used to think the same, but now think that is just
wrong. Again, the example of The Calculus and such come to mind...

Not sure what you mean about calculus.
 
P

Paul Rubin

Pascal Costanza said:
It's funny: Language designers have been spending a lot of effort over
the decades on designing language constructs that help to improve the
opportunities to reuse of software libraries. Yet every five years, or
so, new languages and technologies come up that require everyone to
start from scratch. Starting from scratch is even being applauded, due
to some mythical belief that "this time, we are going to get it all right."

What leads to the best work in language research is not necessarily
what leads immediately to the most useful tools for software
developers.
 
P

Paul Rubin

Robert Uhl said:
I'm pretty certain it could be done with conditions.

It's worse than that, there was a big sub-thread about it, conclusion
seems to be it can be done but you need a code walker. I'd consider
that pretty messy, but at least slightly within the scope of
"reasonable".
 
P

Paddy

Robert said:
Of course, you use prefix notation all the time in Python:

for x in range(0,len(y)):
dosomething(x)

In Python, most containers are directly iterable so we are much more
likely to arrange our program to use:
for a in y:
dosomethingwith(a)

-Paddy.
 
P

Paul Rubin

Slawomir Nowaczyk said:
#> Lisp interpreters are several orders of magnitude faster than Python,
#> and Lisp compilers are faster yet. Speed's not the most important
#> thing, but it is _an_ important thing; all other things being equal,
#> the faster solution is better.

Sure. But in 20-30 years, Python might get there.

I think compiled "Python" code may get as Lisp code sooner than that,
but I put "Python" in quotes because I think the language is going to
have to diverge somewhat from the current dialect to get that level of
performance.
 

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,434
Messages
2,571,689
Members
48,796
Latest member
Greg L.

Latest Threads

Top