merits of Lisp vs Python

K

Kaz Kylheku

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



Actual Lisp session transcript:

[1]> (load "infix.cl")
;; Loading file infix.cl ...
;;;
*************************************************************************
;;; Infix notation for Common Lisp.
;;; Version 1.3 28-JUN-96.
;;; Written by Mark Kantrowitz, CMU School of Computer Science.
;;; Copyright (c) 1993-95. All rights reserved.
;;; May be freely redistributed, provided this notice is left intact.
;;; This software is made available AS IS, without any warranty.
;;;
*************************************************************************
;; Loaded file infix.cl
T
[2]> #i( if x < y then a = b[j] else a = c[j,j] ^^ w )

*** - EVAL: variable X has no value
The following restarts are available:
USE-VALUE :R1 You may input a value to be used instead of X.
STORE-VALUE :R2 You may input a new value for X.
ABORT :R3 ABORT
Break 1 [3]> :a
[4]> (quote #i( if x < y then a = b[j] else a = c[j,j] ^^ w ))
(IF (< X Y) (SETF (AREF A I) (AREF B J))
(SETF (AREF A I) (EXPT (AREF C J J) W)))


In spite of such possibilities, things like this just don't catch on in
Lisp programming. Once people know that they /can/ get it if they want,
they no longer want it.

What doesn't make sense is writing entire language implementations from
scratch in order to experiment with notations.

I think someone may have been working on a Python interface built on
Common Lisp.

Ah, here!

http://trac.common-lisp.net/clpython/wiki/WikiStart
 
A

Andrew Reilly

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.

That may be true, but lisp's numeric addition operator knows how to add
fixnums, bignums, rationals and whatever the lisp name for floating points
is (imprecise?) -- something that not many (if any) processor instruction
sets can manage. So that's still type-dependent dispatch, which isn't
going to get us to the speeds that we actually see reported unless there's
extra stuff going on. Type inference? Declarations?

Cheers,
 
K

Kay Schluehr

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

Renaming is of course feasible too but it has to be done manually and
likely involves the change of some keyword. If both L1 and L2 define a
repeat_stmt with slightly different semantics they can't be combined -
renaming of rules is not always a big problem since a new package is
created for L3 anyway and scripts that work with L1 and L2 are at least
binary compatible with L3. The clash happens when one tries to edit an
L2 script in an L3 context. One has to refactor it regarding the
renamed rule ( this can very likely be done automatically ).

Since the rule definitions originate in different packages ( each
language is created in an own package ) there is basically no conflict
and one can switch between L1 and L2 and also import L1 in L2 or vice
versa but this is not the kind of composition I intend since one can't
really nest the statements/expressions made in L1 with those made in
L2.
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.

I don't see how this differs. A grammar G is just a "script" written in
another language ( say EBNF ) which can be represented within the sytem
as just another grammar. The internal representation of G is that of a
list of lists. While the programmer manipulates the surface structure
of the Grammar script which could be represented in whatever she likes
( currently as plain text but maybe also as a graph using dot and
graphviz or in any other slick way an UI designer imagines ) all
internal operations are defined on nested lists i.e. objects.
 
P

Paul Rubin

Robert Brown said:
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.

I'd say Python is more dynamic in the sense that the Python runtime
system has to actually concern itself about the dynamism all the time
in practice, i.e. on every object method invocation. The Lisp runtime
only has to think about it when the application calls specific
functions in those interfaces. The rest of the time, it can use
various optimizations like compile-time analysis and caching. I do
not consider this contrast to be in Python's favor.
 
K

Kay Schluehr

Paul said:
I'd say Python is more dynamic in the sense that the Python runtime
system has to actually concern itself about the dynamism all the time
in practice, i.e. on every object method invocation. The Lisp runtime
only has to think about it when the application calls specific
functions in those interfaces. The rest of the time, it can use
various optimizations like compile-time analysis and caching. I do
not consider this contrast to be in Python's favor.

The main complaint I have myself is that the CPython runtime can't even
deal with static information presumed that it is available. Psyco
indeed can do it but it is a plugin and it is not supported and
understood by the whole core development team but only by Armin Rigo
himself. Instead of making up the CPython runtime for better support of
Psyco and related approaches Armin had to start PyPy ( this happened
more than 3 years ago! ) Now we are in the situation that parts of
Python are also RPython which means that their can be analyzed
statically but we need PyPy to compile them into CPython extensions.
This is really weird.
 
E

Espen Vestre

[thank you for clarifying my post, Robert]
I'd say Python is more dynamic in the sense that the Python runtime
system has to actually concern itself about the dynamism all the time
in practice, i.e. on every object method invocation.

Ok, but when you state that language A is more dynamic than language
B, most programmers would interpret that as (or so I guess) "A offers
more dynamism to the programmer than B" - not that it burdens the run
time system implementor with more dynamism...
 
J

Juan R.

Rob Thorpe ha escrito:
It's not fair to pick on him just because you're better at
Googlefighting...

I simply noticed (eval "there is no Monty Ruby to help") --> NIL

There is many "Juan González" but i am not one of them. Try next

http://www.googlefight.com/index.php?lang=en_GB&word1=Ken+Tilton&word2=Juan+R.+Gonz%E1lez+%C1lvarez
http://www.googlefight.com/index.php?lang=en_GB&word1=Ken+Tilton&word2=Robert+Thorpe
I find the results dubious. A conspiracy masterminded by Monty Ruby no
doubt.

With some help from mediocre programmers :)
 
I

I V

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?
 
P

Pekka Karjalainen

I think that's some kind of proposed or experimental Haskell feature,
not in the current standard, but I'm not sure. I'm barely even a
newbie with Haskell.

It's called Template Haskell.

http://www.haskell.org/th/

"Template Haskell is an extension to Haskell 98 that allows you to do
type-safe compile-time meta-programming, with Haskell both as the
manipulating language and the language being manipulated."

There is an experimental implementation in new versions of GHC.

Follow-ups set to comp.lang.haskell in case anyone wants to discuss it. I
claim no understanding of it yet. Better figure out ordinary Haskell
first...
 
I

I V

We're not counting lines here, you goon. We're talking about how
expressive constructs are and how closely they match your concept of
what you want to do. The conditional example is lower-level; you're
talking to the interpreter instead of saying what you want to achieve.
You're having to repeat things because that's what the language asks
of you, instead of describing in a higher-level way what you're
actually doing.

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.

One of the things I've always found off-putting about lisp as that all the
syntax looks the same. In Algol-derived languages, each syntactic
construct has a fairly distinctive appearance, so when, for instance, I
encounter a for loop, I can quickly recognize that that's what it is, and
bracket out the "scaffolding" and pick out the details that interest me.
With lisp, I can't do that, I have to read through the sexp, decide on
what syntax it is, and then remind myself where to look for the relevant
specific details.

Now, this might well be just due to my comparative lack of familiarity
with lisp; I'd be interested to hear if you lisp people find different
lisp constructs as visually distinctive as constructs in python (or other
similar languages). But I think what people are getting at when they
complain about "all the brackets" in lisp may actually be this issue of
a visual distinction between different constructs (this is also a reason
why having a limited number of syntactic constructs can be helpful - there
are a probably a limited number of stereotypical layouts a programmer can
keep in their mind at once).
 
J

Juan R.

Kay Schluehr ha escrito:
My approach is strongly grammar based. You start with a grammar
description of your language. This is really not much different from
using Lex/Yacc except that it is situated and adapted to a pre-existing
language ecosystem. I do not intend to start from scratch.

Besides the rules that constitute your host language you might add:

repeat_stmt ::= 'repeat' ':' suite 'until' ':' test

The transformation target ( the "template" ) is

while True:
<suite>
if <test>:
break

The structure of the rule is also the structure of its constituents in
the parse tree. Since you match the repeat_stmt rule and its
corresponding node in the parse tree you immediately get the <suite>
node and the <test> node:

class FiberTransformer(Transformer):
@transform
def repeat_stmt(self, node):
_suite = find_node(node, symbol.suite)
_ test = find_node(node, symbol.test, depth = 1)
#
# create the while_stmt here
#
return _while_stmt_node

So analysis works just fine. But what about creating the transformation
target? The problem with the template above is that it can't work
precisely this way as a Python statement, because the rule for a while
statement looks like this:

while_stmt: 'while' test ':' suite

That's why the macro expander has to merge the <suite> node, passed
into the template with the if_stmt of the template, into a new suite
node.

Now think about having created a while_stmt from your original
repeat_stmt. You return the while_stmt and it has to be fitted into the
original syntax tree in place of the repeat_stmt. This must be done
carefully. Otherwise structure in the tree is desroyed or the node is
inserted in a place where the compiler does not expect it.

The framework has to do lots of work to ease the pain for the meta
programmer.

a) create the correct transformation target
b) fit the target into the syntax tree

Nothing depends here particularly on Python but is true for any
language with a fixed grammar description. I've worked exclusively with
LL(1) grammars but I see no reason why this general scheme shall not
work with more powefull grammars and more complicated languages - Rubys
for example.
Thanks.


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.

You mean direct compositionality. Is there any formal proof that you
cannot find a (G2' , T2') unambiguously generating (G2, T2) and
combining with L1 or this is always possible?

This would not work for language enhancements but for composition of
completely independent languages.
 
J

Juan R.

Kaz Kylheku ha escrito:
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.

Or simply namespacing!

foo from package alpha --> alpha:foo

foo from package beta --> beta:foo

But what composition of different languages? E.g. LISP and Fortran in
the same source.
 
J

Juan R.

greg ha escrito:
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.

I see no dinamism on your example, just static overloading.
 
K

Kay Schluehr

Juan said:
You mean direct compositionality. Is there any formal proof that you
cannot find a (G2' , T2') unambiguously generating (G2, T2) and
combining with L1 or this is always possible?

You mean a universal language adapter? I guess this is always possible
using alpha conversion but I don't believe this leads to theoretical or
practical interesting solutions but is just a limit concept.
This would not work for language enhancements but for composition of
completely independent languages.

The practical problem with composing enhancements is that any two
extensions L1, L2 share a lot of rules and rely on their structure.
What if they don't just extend their host language L0 conservatively
but also redefine rules of L0? This is not just a theoretical problem
but it happens quite naturally if you want to adapt an extension
developed for Python 2.4 for working with Python 2.5. Here Python 2.5
is considered as just another particular extension. Obviously Py3K will
become an interesting testcase for all kinds of syntactical and
semantical transformations.
 
K

Kay Schluehr

I said:
One of the things I've always found off-putting about lisp as that all the
syntax looks the same. In Algol-derived languages, each syntactic
construct has a fairly distinctive appearance, so when, for instance, I
encounter a for loop, I can quickly recognize that that's what it is, and
bracket out the "scaffolding" and pick out the details that interest me.

I guess towards the intentional programming guys around Charles Simonyi
also all Algol languages look roughly the same. I remember how annoyed
I was as a math student that no PL supported my familiar notations
directly. I don't even try to speculate what chemists think about ASCII.
 
P

Pascal Costanza

I said:
One of the things I've always found off-putting about lisp as that all the
syntax looks the same. In Algol-derived languages, each syntactic
construct has a fairly distinctive appearance, so when, for instance, I
encounter a for loop, I can quickly recognize that that's what it is, and
bracket out the "scaffolding" and pick out the details that interest me.
With lisp, I can't do that, I have to read through the sexp, decide on
what syntax it is, and then remind myself where to look for the relevant
specific details.

May you have tried the wrong Lisp dialects so far:

(loop for i from 2 to 10 by 2
do (print i))


This is Common Lisp. (Many Lisp and Scheme tutorials teach you that you
should implement this using recursion, but you really don't have to. ;)


Pascal
 
P

Paul Rubin

Espen Vestre said:
Ok, but when you state that language A is more dynamic than language
B, most programmers would interpret that as (or so I guess) "A offers
more dynamism to the programmer than B" - not that it burdens the run
time system implementor with more dynamism...

I'm sorry for any misunderstanding. Maybe I should have said that
Python's dynamism is more pervasive: it can be activated in more
different ways and that creates an extra burden on the runtime system.
Remember that the context was whether Python could be compiled to
efficient machine code. So I referred to "more dynamism" from the
implementers' point of view--the runtime has to pay attention to more
things and spend more resources dealing with the dynamism.

I think the Lispies see "more dynamism" as a good thing and are
therefore defending their language from suggestions that Python is
even more dynamic than Lisp. I mean "dynamic" in a less good way--
there is a huge amount of state scattered all through a running Python
program, that the application can modify at random and whose contents
the working of really fundamental operations like method invocation.
It's just a big mess and I'd get rid of it if I could. It reminds me
of like old time Lisp programs that pervasively used property lists on
symbols to attach random attributes to the symbol, instead of using
something like defstruct to make multi-field data values.

How about if I say Python and Lisp are both dynamic, but Lisp does a
better job of keeping its dynamism's potentially chaotic effects
contained. Does that help?
 
P

Paul Rubin

I V said:
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.
 

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