merits of Lisp vs Python

P

Paul Rubin

HowiPepper said:
With Python's ease of learning and use, availability of a large number
of libraries, extremely active development community and large
user-base, I'd say the question to ask is what specific advantages over
Python does Lisp offer, to make people switch to it?

Lisp has a more uniform design geared towards large system
development. It doesn't have as many weird quirks and exceptions as
Python. It has much more serious implementations with real compilers.
There is an inevitability about the way the language works, it's just
"cosmic". The only way I can suggest to appreciate that is study an
implementation of it sometime. The parentheses really aren't a big
deal. Lisp is simply hypnotic, to those receptive to that kind of
thing. In musical terms, Python is like a Beatles song, very popular
and easy to sway and dance to. Lisp is like a Bach fugue.
 
P

Paul Rubin

Espen Vestre said:
Just as I said: Less managable, but not more dynamic.

I'm not getting through to you. Yes, you could create a Python-like
object system in Lisp that's separate from CLOS, but nobody would use
it. It wouldn't matter whether you could compile it efficiently or
not, since nobody would care. What matters is that you can compile
CLOS efficiently.

Python's object system is used in every Python program and it has
those properties and if you try to remove them, you don't have Python
any more. A Python compiler has to deal with that. So compiled
Python code is necessarily going to suffer compared with compiled Lisp
code.
 
G

Greg Menke

Paul Rubin said:
André Thieme said:
Yes, I mentioned that a bit earlier in this thread (not about the
"during runtime" thing).
I also said that many macros only save some small bits of code.
Your python example contains 4 tokens / brain units.
The Lisp version only has 2.

You shouldn't count the import statement, since you'd need the
equivalent in Lisp as well.

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.


Not really. The syntax of getting and setting array elements isn't
really the point. It ignores the cognitive efficiency of Lisp when
things get more complex, and likewise whatever similar characteristics
that Python offers. I don't mean to imply Python is inefficient, just
that array manipulation syntax isn't where the two languages' strengths
& weaknesses appear. To compare the languages when things get
complicated, in effect, to see how they help and how they hurt when
problems are difficult, then a more complex example is necessary. Since
the arguments so far seem dominated by syntactical trivia, they seem to
me more about perceived aesthetics and personal preference than anything
else.

I spent a year or so using Python as a scripting language for relatively
simple applications where shell scripts were insufficient. It works
fine as such. But it began to suck performance-wise when I started
trying to manipulate more complex datasets and I began wanting
compilation to get throughput up. Common Lisp, being a highly mature
language (and thus sometimes ossified in appearance), offered a
standardized language with a variety of implementations, some of which
gave me the compiler tools I needed without forcing me to retool
concepts and source code from the freebie implementations I started
with. This is a very important point once there is considerable
conceptual investment in a suite of source.

When the New & Cool arguments are presented, this issue seems neglected.
There are many tradeoffs to be made between New & Cool and Highly
Matured, syntax being only one.

Gregm
 
P

Paul Rubin

Greg Menke said:
a = b[n] with
(setf (aref a i) (aref b n))


Not really. The syntax of getting and setting array elements isn't
really the point. It ignores the cognitive efficiency of Lisp when
things get more complex, and likewise whatever similar characteristics
that Python offers.


Well, there's some similar way to look up elements in a Lisp
hashtable, but I've forgotten the keyword for it (oops, cognitive
inefficiency, having to remember separately.) Python uses the same
syntax for both.

Yeah it's probably true that very complex applications are easier to
develop in Lisp. For small and medium ones, I really do find Python
more pleasant, and I'm speaking as someone for whom the discovery of
Lisp was once an unbelievably powerful epiphany.
 
P

Piotr

Paul said:
a = b[n]
(setf (aref a i) (aref b n))


Well, there's some similar way to look up elements in a Lisp
hashtable, but I've forgotten the keyword for it (oops, cognitive
inefficiency, having to remember separately.) Python uses the same
syntax for both.


That's true, Lisp would benefit from _standard_ homogenuous polymorphic
accessor functions to list-like objects and/or low-level (macro-like)
syntactic sugar. Yes, you can easily make (a i) act like (aref a i)
but it is not done by default. Legacy reasons? Graham has interesting
things to say about this issue:

http://www.paulgraham.com/ilc03.html

Most of my programs are also written in Python, however, I would say
that in many cases "a = b[n]" is an artefact of programming habits
from C, which has no language support for list comprehension,
iterators, etc. I tend to avoid such constructs; usually there is a
more natural way to do the same and it's just too easy to get the
indices wrong.

Piotr
 
J

Jan Dries

Paul said:
In musical terms, Python is like a Beatles song, very popular
and easy to sway and dance to. Lisp is like a Bach fugue.

While I agree with your point in principle, I think that comparing
Python to a Beatles song doesn't give the language the credit it IMO
deserves. To avoid another thread like this one I will not state what
language I would compare to a Beatles song, but if Lisp is a Bach fugue
then Python I think is more like Mozart. Sure, Bach is the ultimate
Master, no doubt. But Mozart wrote some damn fine music, often heavily
borrowing ideas not only from Bach but also other masters (Handel for
instance), but turning the whole into "something popular and easy to
sway and dance to".

Come to think of it, there definitely is something pythonic to Mozart ...

Regards,
Jan
 
P

Pillsy

Piotr said:
Paul Rubin wrote: [...]
Well, there's some similar way to look up elements in a Lisp
hashtable, but I've forgotten the keyword for it (oops, cognitive
inefficiency, having to remember separately.)

FWIW, the command is GETHASH. The situation in CL is actually even
worse than just having different names for these functions, since some
functions put the index as the first argument (GETHASH, NTH) and others
put it as the second argument (AREF, ELT). You can at least hide this
archaic nonsense away by defining methods for a generic function if it
bugs you.
That's true, Lisp would benefit from _standard_ homogenuous polymorphic
accessor functions to list-like objects and/or low-level (macro-like)
syntactic sugar. Yes, you can easily make (a i) act like (aref a i)
but it is not done by default. Legacy reasons?

Well, it's not such a hot idea in a Lisp-2, since you'll often have a
variable named, say, LIST, and then the meaning of (LIST 1) becomes
ambiguous.

In CL, you could do the implicit indexing with different braces,
though, like [a i] for (aref i); this is something I periodically
consider doing.

Cheers,
Pillsy
 
K

Kaz Kylheku

Kay said:
Given two languages L1 = (G1,T1), L2 = (G2, T2 ) where G1, G2 are
grammars and T1, T2 transformers that transform source written in L1 or
L2 into some base language
L0 = (G0, Id ). Can G1 and G2 be combined to create a new grammar G3
s.t. the transformers T1 and T2 can be used also to transform L3 = (G3
= G1(x)G2, T3 = T1(+)T2) ? In the general case G3 will be ambigous and
the answer is NO. But it could also be YES in many relevant cases. So
the question is whether it is necessary and sufficient to check whether
the "crossing" between G1 and G2 is feasible i.e. doesn't produce
ambiguities.

See, we don't have this problem in Lisp, unless some of the transfomers
in T1 have names that clash with those in T2. That problem can be
avoided by placing the macros in separate packages, or by renaming. In
In the absence of naming conflicts, the two macro languages L1 and L2
combine seamlessly into L3, because the transformers T are defined on
structure, not on lexical grammar. The read grammar doesn't change (and
is in fact irrelevant, since the whole drama is played out with
objects, not text). In L1, the grammar is nested lists. In L2, the
grammar is, again, nested lists. And in L3: nested lists. So that in
fact, at one level, you don't even recognize them as being different
languages, but on a different level you can.

The problems you are grappling with are in fact created by the
invention of an unsuitable encoding. You are in effect solving a puzzle
that you or others created for you.
 
R

Robert Brown

Paul Rubin said:
I'm not getting through to you. Yes, you could create a Python-like
object system in Lisp that's separate from CLOS, but nobody would use
it ....

I think you are not understanding the point that Espen is trying to make.
He is not suggesting a different object system for Lisp.

Espen is saying that Common Lisp often offers the same dynamic feature as
Python has, such as the ability to redefining a method at runtime. Lisp,
however, forces you to call a CLOS function or use an well defined interface
when redefining a method. You can't just change a value in a hash table.
Does this make Lisp "less dynamic" than Python? Espen would say it's not
less dynamic, but rather that a similar level of dynamism is achieved in
Common Lisp via well defined interfaces. The compiler knows the interfaces,
so it can do a better job optimizing the code.
 
G

greg

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.

For selecting a single form, that's true. For
more than one form (such as selecting some, but
not all, of the statements in a loop body) it's
not much different.

But my point was that I don't find "manually
reindenting the lines" to be a chore. He made it
sound like you have to laboriously go through
and adjust the lines one by one, but it's not
like that at all. You shift them all at once
in a block.
How extensively?

Enough to know what I'm talking about. Tens
of thousands of lines of Lisp and Scheme, and
hundreds of thousands of lines of Python, I
would estimate.

Seeing as you asked, how much Python code have
you or Ken edited?
 
G

greg

So if you guys would just fix
your language by adding homogeneous syntax and all that it brings with
it (macros, compilers, etc) we'd be happy to use your version of Lisp,
and all its great libraries, instead of ours! :)

But if we did that, it wouldn't be Python any
more, it'd be Lisp. And then all those great
libraries wouldn't work with it, because they're
for Python, not Lisp. :-(
 
G

greg

Bill said:
A compiler shifts a lot of decisions that an
interpreter would have to make at runtime to compile-time. There is
no reason a dynamic language can't enjoy this efficiency.

I'm not saying that it's impossible to compile
Python, only that's there's a lot more to it than
just macro expansion. The OP was saying something
like "If you added macros, you might get a compiler
for free", which is clearly far from true.
if Python is doing a hash lookup on every function call,
as Alex Mizrahi claims, compilation may not do much to smooth over
such awkwardness.

As currently implemented, CPython does a dictionary
lookup or two every time a module global or builtin
(which most stand-alone functions are) is referenced.
It would actually be relatively easy to optimise this
into an array lookup in most cases, but most calls in
Python code tend to be *method* calls, which are rather
harder to deal with. Possibly cacheing of method
lookups would help, although I don't know of anyone
having tried it.
Uh huh. "More so than Lisp"? Just making stuff up now?

When a Lisp compiler sees

(setq c (+ a b))

it can reasonably infer that the + is the built-in numeric
addition operator. But a Python compiler seeing

c = a + b

can't tell *anything* about what the + means without
knowing the types of a and b. They might be numbers, or
strings, or lists, or some user-defined class with its
own definition of addition.

From another angle, think about what a hypothetical
Python-to-Lisp translator would have to do. It couldn't
just translate "a + b" into "(+ a b)". It would have
to be something like "(*python-add* a b)" where
*python-add* is some support function doing all the
dynamic dispatching that the Python interpreter would
have done.

That's what I mean by Python being more dynamic than
Lisp.
Despite its dynamism, Lisp is quite compilable.

Please correct me if I'm wrong, but as I understand,
getting efficient code out of a Lisp compiler requires
putting type declarations into the source.

If you put the same declarations into a piece of
Python code, then of course it would be fairly
straightforward to compile it efficiently. But it
wouldn't really be dynamic Python any more.

Python may end up going this way -- there are
currently plans to make room for attaching optional
annotations to function arguments, which could be
used to convey type information to a compiler
(although that's not currently the main intended
use).

The alternative is whole-program analysis and huge
amounts of type inferencing, which the PyPy people
are working on. Maybe something practical will come
out of that.

Whichever, it's nowhere near a simple as just
"adding macros"!
 
R

Robert Brown

Stephen Eilert said:
So, let's suppose I now want to learn LISP (I did try, on several
occasions). What I would like to do would be to replace Python and code
GUI applications. Yes, those boring business-like applications that have
to access databases and consume those new-fangled web-services and
whatnot. Heck, maybe even code games using DirectX.

So, how would I do that?

First, get a copy of Practical Common Lisp, which shows how to build, well,
practical programs in Lisp:

http://www.gigamonkeys.com/book/

Next, download a Common Lisp implementation. I happen to prefer SBCL, but
any of the free commercial trial products will do, as will CLISP, CMUCL,
ABCL, Open MCL, etc.

To find libraries, look in Cliki, in the Common Lisp Directory, and in
Common-Lisp.net. The Directory is especially good for finding obscure
stuff.

http://www.cliki.net/
http://www.cl-user.net/
http://common-lisp.net/

Bookmark the Hyperspec, which is an HTML version of the ANSI Common Lisp
standard. Skim the whole thing once, so you have a vague idea of what
functions are available in the standard library.

http://www.lispworks.com/documentation/HyperSpec/Front/index.htm

Finally, ask questions on the #lisp IRC channel or in comp.lang.lisp when
you are stuck.
 
J

Jan Dries

Robert said:
I think you are not understanding the point that Espen is trying to make.
He is not suggesting a different object system for Lisp.

Espen is saying that Common Lisp often offers the same dynamic feature as
Python has, such as the ability to redefining a method at runtime. Lisp,
however, forces you to call a CLOS function or use an well defined interface
when redefining a method. You can't just change a value in a hash table.
Does this make Lisp "less dynamic" than Python? Espen would say it's not
less dynamic, but rather that a similar level of dynamism is achieved in
Common Lisp via well defined interfaces. The compiler knows the interfaces,
so it can do a better job optimizing the code.

Isn't that the same as saying "less dynamic" by the very meaning of the
word in this context? The more the compiler knows or can deduce at
compile time, the more static. At least that has always been my view on it.

Regards,
Jan
 
G

Greg Johnston

Stephen said:
So, let's suppose I now want to learn LISP (I did try, on several
occasions). What I would like to do would be to replace Python and code
GUI applications. Yes, those boring business-like applications that
have to access databases and consume those new-fangled web-services and
whatnot. Heck, maybe even code games using DirectX.

DrScheme for the first. Oh...well, there's loads of OpenGL support if
you can bear using that instead of DirectX. If you want CL, cl-opengl
and cells-gtk seem to work well.
So, how would I do that? For Python, that was simple. I learned the
basics, then moved to the libraries, learning as I went. Python has
some excelent online resources.

http://www.gigamonkeys.com/book/ (Practical Common Lisp)
http://www.paulgraham.com/onlisp.html (On Lisp)
http://www.htdp.org/ (HTDP)
http://mitpress.mit.edu/sicp/ (SICP)
http://schemecookbook.org/
http://www.cliki.net/index
(Note: I mixed Scheme and CL pages above)

Not sure what other online resources you want.
No, I don't want to see yet another Fibonacci example. No, console
output is not fun. And yes, I know about this list processing stuff.
All I can find are introductions to LISP written for computer science
courses. I can't seem to put together all those mnemonics into a
working program. LISP is full of primitives with 3-4 characters, chosen
for historical reasons.

You're welcome to use things like first, rest, or second instead of
car, cdr, or cadr, but I always find the latter easier (car and cdr are
composable, and remind you that you're using cons cells). What other
mnemonics are there? I guess cons, but that shouldn't be hard...

On the other hand, Python has no 3-letter words. *struck dead by a
flying "def"*
 
J

JShrager

greg said:
But if we did that, it wouldn't be Python any
more, it'd be Lisp. And then all those great
libraries wouldn't work with it, because they're
for Python, not Lisp. :-(

Does the word "TRONDANT" hold some special meaning for you?
 
K

Ken Tilton

greg said:
For selecting a single form, that's true. For
more than one form (such as selecting some, but
not all, of the statements in a loop body) it's
not much different.

But my point was that I don't find "manually
reindenting the lines" to be a chore. He made it
sound like you have to laboriously go through
and adjust the lines one by one, but it's not
like that at all. You shift them all at once
in a block.

It is a gray area. Manually maintaining indentation does not have to be
a "laborious chore" to slow down development.

I believe it was in the mid 1980s when I turned to the developer sitting
next to me and said, "I wonder how much time I spend re-tabbing my
code?" That was probably Vax Basic or COBOL. I /think/ the editor had a
block-tab capability, and I think I used same in some C IDES, but to be
honest retabbling a few lines was not such a laborious chore <g> that I
would first do the select operation to be able to use it.

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.

Finally, Python is just a (fine) scripting language. Which means one
does not tackle hard problems with it, the kind one figures out as one
goes. That means less refactoring, and less refactoring means less
slicing and dicing of the code.

Seeing as you asked, how much Python code have
you or Ken edited?

See above. Not Python, but out the wazoo in other languages.

Remember, we are not Lisp-only aliens, we program all the languages you
program, plus one. :)

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
 
K

Ken Tilton

greg said:
But if we did that, it wouldn't be Python any
more, it'd be Lisp.

And someone would then have to invent Python.

Let Python be Python, let Lisp be Lisp. It's all good.

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
 
R

Robert Brown

greg said:
From another angle, think about what a hypothetical Python-to-Lisp
translator would have to do. It couldn't just translate "a + b" into
"(+ a b)". It would have to be something like "(*python-add* a b)" where
*python-add* is some support function doing all the dynamic dispatching
that the Python interpreter would have done.

Luckily, Willem Broekema has written a Python to Lisp compiler called
clpython that can be consulted to answer questions like these.

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

It turns out that addition is fairly straightforward. Attribute lookup,
however, turns out to be complex, as is comparing objects. Here is Willem's
description of the attribute lookup algorithm from the file doc/pres.txt:


To look up person.name (the "name" attribute of object "person")

a. if the class of "person" (say, Person), or one of Person's
base classes (say, Animal) defines __getattribute__,
that will intercept all attribute lookups.
Call: Animal.__getattribute__(person, name)

b. look in instance dictionary: val = person.__dict__["name"]

- but if it has fixed slots:
look in person.__slots__
and give error if "name" is not one of the fixed slots

- unless "__dict__" is specified as one of the fixed slots:
in that case, don't give an error if it is not one of the
fixed slots, but search in the instance dictionary too

c. look in the classes Person, Animal for an attribute called "name"

- if it is a `descriptor', call its __get__ method
- else, if it is a method, make it a bound method
- else, return it unchanged

d. if nothing found so far: look for __getattr__ method in the
classes, and call it: C.__getattr__(person, "name")
 

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

No members online now.

Forum statistics

Threads
474,434
Messages
2,571,690
Members
48,796
Latest member
Greg L.

Latest Threads

Top