merits of Lisp vs Python

G

greg

Is this so unconscious that you don't recognize you are doing it, even
though you take a sentence to explain what you had to do to work around
it?

Yes, it is pretty unconscious. We all do many things
unconsciously in everyday life that would take at
least one sentence to explain to someone else if we
had to think about it.

Besides, in many cases the required brackets are
already there -- e.g. if it's a list, or a function
call with many arguments -- in which case you don't
have to add anything at all.
Adding parentheses ... all this is a
burden specific to Python.

As opposed to Lisp, where all you have to do is
use parentheses... oh, er...
By the way, you guys seem fixate on the parentheses of Lisp without
having the experience

I don't know about the other Pythonistas in this
discussion, but personally I do have experience with
Lisp, and I understand what you're saying. I have
nothing against Lisp parentheses, I just don't agree
that the Lisp way is superior to the Python way in
all respects, based on my experience with both.
 
G

greg

Ken said:
What if it turns into an SQL lookup during refactoring?

If the macro can produce SQL code, then whatever interprets the
table can produce SQL code as well.

If you're thinking of the macro taking apart the user's reverse
function (rather than just wrapping it) and somehow translating
it into SQL, well... a macro *could* do that, but it would be
an awfully hairy thing to do, especially if the user is allowed
to write arbitrary Lisp code in the body of his function (as
it seems he is, in your example).

A better way would be to design an abstract API for the user
to use in his reverse functions. Then you can just re-implement
the functions making up the API so that they do SQL queries
instead of whatever they were doing before. No macro processing
needed then.
The last example showed the macro inserting code to magically produce a
binding inside the reverse function.

Are you sure? It looked to me like it was adding code *around*
the reverse function, not inside it. I posted a Python function
that achieves the same thing by calling the existing reverse
function.
It would be easier to compare and
contrast with the Python equivalent if someone had posted such, but your
troops have fallen back to Fort So What? and pulled up the drawbridge.

I'm still trying, but some of the code you posted is rather
impenetrable without knowing a lot more about the details of
your system. I'm doing my best to show some Python demonstrating
the gist of what could be done.
 
G

greg

Willem said:
I guess in part it's because there are not that many people really into
both Python and Lisp, and those who are might not find this an
interesting project because there is nothing "wow" to show, yet.

Another reason (or maybe the reason for the reason) is
that people are usually interested in Python because it's
a relatively simple and lightweight thing.

Having to install a complex and heavyweight thing like
a Common Lisp system just to be able to program in
Python doesn't seem like a good deal.

It might become a good deal if you could then compile
the Lisp and get a lean, efficient binary executable
out of it. But that's going to require much more than
just a straightforward translation from Python to Lisp.

If CLPython starts to show signs of making progress
in that direction, then it could start to get
interesting. Although I think I'd rather target Scheme
than CL if I were doing it -- cleaner language, small
yet still extremely good implementations available.
 
P

Paul Boddie

greg said:
Another reason (or maybe the reason for the reason) is
that people are usually interested in Python because it's
a relatively simple and lightweight thing.

I think it's more likely that the Lisp people wonder why you'd want to
write anything other than Lisp (and they're all supposedly too busy
doing other things, anyway, like rewriting their own version of
reddit.com), whereas the Python people either haven't heard about it,
aren't really interested because they believe other projects (eg. PyPy)
will deliver the same benefits (which probably won't be the case
entirely), or don't have the means to either run and experiment with it
or to help out.
Having to install a complex and heavyweight thing like
a Common Lisp system just to be able to program in
Python doesn't seem like a good deal.

There seems to be a fairly high intuitive similarity between various
Common Lisp concepts and various Python concepts, although one can only
make best use out of Common Lisp features (or the features of any
particular platform) if the correspondence is sufficiently high. I
suppose the argument that one can write extensions in Lisp rather than
C may be enticing, but one returns to the "why write anything other
than Lisp" argument at this point. There may be an argument for having
CLPython as an embedded application scripting language, but again the
Lisp camp have often advocated Lisp for that role, too.
It might become a good deal if you could then compile
the Lisp and get a lean, efficient binary executable
out of it. But that's going to require much more than
just a straightforward translation from Python to Lisp.
Indeed.

If CLPython starts to show signs of making progress
in that direction, then it could start to get
interesting. Although I think I'd rather target Scheme
than CL if I were doing it -- cleaner language, small
yet still extremely good implementations available.

Well, there are some open source Common Lisp implementations around,
despite the obvious bias in certain circles to encourage everyone to
use the proprietary implementations instead, and things like SBCL are
only a simple package manager install away. Meanwhile, there was an
implementation of Python for Scheme, but I don't think the developers
took the idea much further after presenting it at PyCon a few years
ago.

Paul
 
?

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

greg said:
It seems to me your brain is somewhat stuck on the use of macros.

That you see it this way is normal.
A BASIC programmer would tell you the same thing. He can show you
solutions that don't use classes, methods or functions.
Some sweet gotos and gosubs are enough.
The idea is that macros save you tokens and allow you to experess
in a clearer way what you want to do. But in no case one "needs"
them to solve a programming problem. All what Kenny showed could
be done without his macro. It would just be a bit more complicated
and the resulting code wouldn't look good.

> You're looking at the expansion of your
macro and assuming that you'd have to write all that
code by hand if you didn't have macros. You're not
thinking about alternative approaches, which could
just as well be used in Lisp as well as Python, that
are just as compact yet don't make use of macros.

He wouldn't have to write the full expansion. With functional
programming he could also solve it, but then he would need
a funcall here, a lambda there. And his code would not look
so understandable anymore, because it is filled up with some
low level details.


I will take one of the first macro examples form "On Lisp".
Let's say for some reason you want to analyse some numbers
and do something depending on their sign. We want a function
"numeric if":

def nif(num, pos, zero, neg):
if num > 0:
return pos
else:
if num == 0:
return zero
else:
return neg


In Lisp very similar:
(defun nif (num pos zero neg)
(case (truncate (signum num))
(1 pos)
(0 zero)
(-1 neg)))


Now one example Graham gives is:
(mapcar #'(lambda (x)
(nif x 'p 'z 'n))
'(0 2.5 -8))

which results in the list (Z P N).
You can do the same thing in Python.
But it gets hairier if we want to make function calls that
have side effects.
Let me add these three functions:

(defun p ()
(print "very positive")
"positive")

(defun z ()
(print "no no")
"zero")

(defun n ()
(print "very negative")
"negative")


And now see what happens:

CL-USER> (mapcar #'(lambda (x)
(nif x (p) (z) (n)))
'(0 2.5 -8))

"very positive"
"no no"
"very negative"
"very positive"
"no no"
"very negative"
"very positive"
"no no"
"very negative"
("zero" "positive" "negative")

The messages were printed in each case.
To stop that I need lazy evaluation:
CL-USER> (mapcar #'(lambda (x)
(funcall
(nif x
#'(lambda () (p))
#'(lambda () (z))
#'(lambda () (n)))))
'(0 2.5 -8))

"no no"
"very positive"
"very negative"
("zero" "positive" "negative")


I put the calls to the functions p, z and n into a function object.
In some languages it would look a bit cleaner, for example Ruby.
They have a single name space and don't need funcall and lambda is
shorter. But still, we need to add several tokens. Maybe Haskell has
built in support for that.


Now with nif as a macro:
(defmacro nif (expr pos zero neg)
`(case (truncate (signum ,expr))
(1 ,pos)
(0 ,zero)
(-1 ,neg)))

It is a bit more complex as the function. It has one ` and 4 ,s
extra.
But now we can express the problem very well:

CL-USER> (mapcar #'(lambda (x)
(nif x (p) (z) (n)))
'(0 2.5 -8))

"no no"
"very positive"
"very negative"
("zero" "positive" "negative")

And the first example also still works the same way.
Now the expansion shows more code than we would have need to
write ourself. However, now we can write code that matches
much better how we think. No need for "low level" details like
embedding the code inside of anon functions.
This represents what most macros do. Save one or more lambdas
and/or funcalls. One consequence is that development time gets
cut down.


André
--
 
K

Ken Tilton

greg said:
I don't see why you can't just write a function that
loops over the results and calls the user's reversal
function for each one.

That was the original coding, but notice that a derivation (DRV) is an
argument to tf-reverse. Can you say "encapsulation"? :) What if that
changes? It did. I used to have just one result per derivation, until a
multi-result case came along.

Since I will be having many dozens of these I might well try to keep as
much code as possible out of them (encapsulation de damned <g>) to
minimize the inevitable hit when I refactor, but I have macros so I do
not have to.
def reverse_multiple(skill, resx_list, opnds):
for resx in rex_list:
skill.reverse(resx, opnds)

There's no need to macro-expand this code into every
reversal function, when it can be done once as part of
the framework that calls the reversal functions.

Rather than go into "argue mode" before fully understanding the issues,
please note that I am just looking to learn (without judgment) what the
Python equivalent would be. Things I offer are not "you can't touch
this!", they are "what does the Python look like?". Afterwards we can
get into a pissing match. :)

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:
It seems to me your brain is somewhat stuck on the use
of macros. You're looking at the expansion of your
macro and assuming that you'd have to write all that
code by hand if you didn't have macros. You're not
thinking about alternative approaches,...

I think your brain is stuck on flaming. I am not thinking about Python
approaches, I am sking Pythonistas to do that. After understanding my
examples. Unfortunately I do not see the latter really happening, so we
are about done here.

Unless there's something very subtle that I'm missing
(I can't claim to follow exactly what all the code
you posted does in detail) I haven't seen anything
that couldn't be done quite reasonably with an
appropriate data structure and ordinary functions
and methods operating on that data structure.

I did explain the last little fun bit (where reverse code miraculously
got a case-specific "signed-value" parameter bound to exactly the right
bit of math structure). This process works only if you then ask
specifically about that (if anything was unclear--my guess is you did
not try all that hard since you are in argue-mode). The other reason you
may not have understodd is that that is waaaaay meta-cool, so meta I do
understand if it went over your head and I would (have been) happy to
explain had you asked.

Time to put the game on, I think. :)

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
 
P

Paul Rubin

André Thieme said:
def nif(num, pos, zero, neg):
if num > 0:
return pos
else:
if num == 0:
return zero
else:
return neg

def nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]
The messages were printed in each case.
To stop that I need lazy evaluation:
CL-USER> (mapcar #'(lambda (x)
(funcall
(nif x
#'(lambda () (p))
#'(lambda () (z))
#'(lambda () (n)))))
'(0 2.5 -8))

in Python:

def lazy_nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]() # the () at the end means funcall

map(lambda x: lazy_nif(x, p, z, n), (0, 2.5, -8))

"nif" is even cleaner in Haskell, if I have this right:

nif x p z n | (x < 0) = n
| (x == 0) = z
| (x > 0) = p

All Haskell evaluation is automatically lazy, so no lambdas etc. needed.
 
C

Christophe Cavalaria

Paul said:
André Thieme said:
def nif(num, pos, zero, neg):
if num > 0:
return pos
else:
if num == 0:
return zero
else:
return neg

def nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]
Since we are in one liners, let's be even smarter and do it like that :

def nif(num, pos, zero, neg):
return (zero, pos, neg)[cmp(num, 0)]

;)
 
K

Ken Tilton

greg said:
Are you sure? It looked to me like it was adding code *around*
the reverse function, not inside it. I posted a Python function
that achieves the same thing by calling the existing reverse
function.

You are thinking about the results iteration, where you broke
encapsulation. I just reminded you of the magical "signed-value" binding
in a reply to another post of yours.

btw, when looking back at the rest of the code I was reminded I had done
something even wilder (well, maybe as wild) in the transforming code
itself. I say "wilder" in the sense of it being waaaaay cool, having a
flying-without-a-net feeling, yet making coding of dozens and dozens of
these transformations simpler, terser, and less buggy.

Someone had me laughing when they said the actual application of a macro
was nice and simple, but the macro itself was scary. It reminded me of a
cranky but sweet old guy on a project who was outraged upon learning I
was using a finite state machine to handle a shaky exchange between two
processes. He maintained that I was "foisting a crazy scheme on the
bank" which no one would be able to maintain. He actually forced me to
defend it in a group code review, the first they ever had, so don't
think it was a normal process for them, this was war. After my
demonstration on how the FSM would react to either or both processes
going south at any point in the exchange, the crank pronounced his
satisfaction with the approach and said, "OK, that is simple. The
infinite-state thing is complicated, but the way it works is simple."
That really made the whole thing worthwhile. :)
I'm still trying, but some of the code you posted is rather
impenetrable without knowing a lot more about the details of
your system. I'm doing my best to show some Python demonstrating
the gist of what could be done.

Great. That's the spirit. But how do we move forward if you just express
global confusion? See if you can understand the magical binding of the
parameter "signed-value". The reverse function will be called by the
engine to reverse a mathematical transformation, in this case simply
taking the absolute value. The generic engine has no way of knowing out
of all the targets, results, and operands (targets from a "before"
expression relocated in their incarnation in the expression operated on)
recorded by a transformation to pass in that position. When I code that
reverse function, I just want to work on the signed-value, as identified
in hard-code fashion by the transformation. ie, All I need do is
coordiate the TF and its reverser. If the reverser needs something else,
say the "coefficient" (this would be a add-like-terms TF), I just go to
the add-like-terms and have it tag the coefficients with the symbol
'coefficient, then I can code:

(reverse (coefficient literal-part)...)

Ah. Time to refactor. I will have multiple coefficients, and when
multiples are expected I want all the input math forms searched for
those tagged coefficient. Any ideas out there? :) It is so tempting to
add an s and have the macroexpansion look for a trailing s in the
symbol-name, but then I am bound to have some singular and in s. Ah,
grep to the rescue: (reverse (literal-part coefficient+)...)

Sweet. By using + I can even have the macroexpansion insert an assertion
that there is at least one. Of course there should be at least two or
this TF would not fire. And so it goes...

:)

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
 
?

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

Paul said:
André Thieme said:
def nif(num, pos, zero, neg):
if num > 0:
return pos
else:
if num == 0:
return zero
else:
return neg

def nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]

That is a nice idea. I can do the same in Lisp, but have to do it
without syntactic sugar which makes it longer, characterwise:

(defun nif2 (num pos zero neg)
(nth (1+ (truncate (signum num)))
(list pos zero neg)))

What Python has is cmp. That is doing what truncate+signum do in
Lisp. So that makes the biggest difference. Another one is that Lisps
signum keeps the datatype:
cmp(5.3, 0) => 1
(signum 5.3) => 1.0

Or also with complex numbers [syntax #C(real, img)]:
(signum #C(10 4)) => #C(0.9284767 0.37139067)

Anyway, from the complexity the Lisp version is a bit better.
The Python version has 11 tokens:
return, tuple-reference, comma, neg, zero, pos, +, 1, cmp, num, 0

and the Lisp version has only 9:
nth, 1+, truncate, signum, num, list, pos, zero, neg

(I didn't count the function head, because both have the same
token count).


The messages were printed in each case.
To stop that I need lazy evaluation:
CL-USER> (mapcar #'(lambda (x)
(funcall
(nif x
#'(lambda () (p))
#'(lambda () (z))
#'(lambda () (n)))))
'(0 2.5 -8))

in Python:

def lazy_nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]() # the () at the end means funcall

map(lambda x: lazy_nif(x, p, z, n), (0, 2.5, -8))

We could do the same in Lisp:

(defun lazy-nif (num pos zero neg)
(funcall (nth (1+ (truncate (signum num)))
(list pos zero neg))))

Here the token count is 12py vs 10cl.
CL-USER> (mapcar #'(lambda (x) (lazy-nif2 x #'p #'z #'n))
'(0 2.5 -8))

"no no"
"very negative"
"very positive"
("zero" "negative" "positive")

But there is a disadvantage:Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 2, in lazy_nif
TypeError: 'str' object is not callable

I don't know how I can fix that. Maybe you could tell me.
In Lisp I would just go with the macro. That works for all cases.

"nif" is even cleaner in Haskell, if I have this right:

nif x p z n | (x < 0) = n
| (x == 0) = z
| (x > 0) = p

All Haskell evaluation is automatically lazy, so no lambdas etc. needed.

Yes, that was what I already supposed.
Do you also know how I can "deactivate" lazyness?


André
--
 
W

Wade Humeniuk

Paul said:
"nif" is even cleaner in Haskell, if I have this right:

nif x p z n | (x < 0) = n
| (x == 0) = z
| (x > 0) = p

All Haskell evaluation is automatically lazy, so no lambdas etc. needed.

You can use that style in CL.

(defun nif (x p z n)
(or (when (< x 0) n)
(when (= x 0) z)
(when (> x 0) p)))


Wade
 
?

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

Christophe said:
Paul said:
André Thieme said:
def nif(num, pos, zero, neg):
if num > 0:
return pos
else:
if num == 0:
return zero
else:
return neg
def nif(num, pos, zero, neg):
return (neg, zero, pos)[cmp(num, 0)+1]
Since we are in one liners, let's be even smarter and do it like that :

def nif(num, pos, zero, neg):
return (zero, pos, neg)[cmp(num, 0)]

Okay, that reduces the complexity of the Python version to that of Lisp.
Now both have the same token count.


André
--
 
P

Paul Rubin

Wade Humeniuk said:
You can use that style in CL.

(defun nif (x p z n)
(or (when (< x 0) n)
(when (= x 0) z)
(when (> x 0) p)))

Yeah but you can't apply it the same way.

[nif x p z n | x <- [0,2.5,-8]]

evaluates exactly one of p, z, or n, for each of the args in that
list. Side effects don't work the same way either, you have to use
special declarations around code with side effects. I'm not yet
conversant enough with Haskell to know how to do it for this example
though.
 
P

Paul Rubin

André Thieme said:
and the Lisp version has only 9:
nth, 1+, truncate, signum, num, list, pos, zero, neg

Oh come on, you have to count the parentheses too.

Anyway, token count doesn't mean much, you have to instead go by the
user's cognitive effort in dealing with the prefix notation etc.,
which isn't purely a matter of token count. And if (+ 2 3) were
really as easy to read as 2+3, mathematics would have been written
that way all along.
TypeError: 'str' object is not callable
I don't know how I can fix that. Maybe you could tell me.

Yes, that was what I already supposed.
Do you also know how I can "deactivate" lazyness?

There's a Haskell builtin called 'seq' which forces evaluation but
again I'm not sure precisely how to apply it here.
 
P

Pascal Bourguignon

Paul Rubin said:
Oh come on, you have to count the parentheses too.

No. Parentheses are editor commands. They don't count anymore than
spaces "count" in Python.
 
K

Ken Tilton

Code is data is code

I was hoping no one would make that mistake. :) macros are all about
code is data, but code is not data in Python* so the two words code and
data serve to differentiate them for Pythonistas.

* Taking questions after a keynote to ILC200? where he reiterated that
Python was the same as Lisp for all intents and purposes:

Norvig: "Yes, John?"
McCarthy: "Is code also data in Python?"
Norvig: "No."

End of exchange. :)
- even in Python:

This could be tougher than I thought.
skills_table = [
{
"title": "Absolute Value",
"annotations": ["Bleah bleah", "ho hum", "etc..."],
"hints": ["and so on", "etc..."],
"reverse" : (lambda x: whatever(x))

That does not demonstrate that code is data, that demonstrates that a
lambda is a first-class object (and, yes, Python's lambda is lame).

You will know you have code as data when you can write Python code that
takes apart "whatever(x)" and produces "oh-now-I-get-it(y)". As part of
the language, such that Python applies your transforming code for you
whenever it sees whatever. (Hell, even C has a preprocessor.)
},
{
"title": "Square Root",
"annotations": ["Bleah bleah", "ho hum", "etc..."],
"hints": ["and so on", "etc..."],
"reverse" : (lambda x: someother(x))
},
# etc...
]

Of course those lambdas are crippled in Python (and not really
necessary in this bogus example)... But that's without trying to be
clever:

class AbsoluteValue:
title="Absolute Value"
annotations=["Some list", "goes here"]
@classmethod
def reverse(cls, *args):
# I didn't understand what your code was doing

yeah, and god forbid you should ask. :) this is the crux of the matter!

Actually, it is kinda cool that you and Greg are semi-identifying the
crux by saying "this is the only bit I do not get, I'll skip this, move
on, nothing to see here".
pass
defskill(AbsoluteValue)

That would be a reasonable place for a "pie decorator" on a class, but
I guess that's not allowed.

Hmmm. Actually, that is the whole point, all of Python is allowed.
decorators were used in PyCells, but I never got much of an idea what
they did. Is there a moral equivalent of a macroexpansion for decorators
so you can show the before and after?

I doubt this second example would be
considered "Pythonic" in any case...

exactly what we are looking for in this cultural exchange: how would
Python handle what I am doing with macros in the reverse functions? Make
it as slick and programmer-friendly (cuz I may get to a hundred of these
before I am done with Algebra I) as possible. When all the Pythonistas
proclaim it optimal, then we compare and contrast.

This, btw, is the Tilton Test for language comparison: Not measurements
of programmer effort, rather examination of perfect equivalent code.
PyCells vs Cells would be an amazing case, because that is some hairy
functionality.

Is, too! (ie, I am kinda looking for a specific question that conveys
understanding of the use case.)
Python has plenty of other flaws that I can't happily work around, and
I do think Lisp is more flexible. However, I think your example is
readable enough with a data driven algorithm in most any popular
language. All of the data is visible to the reverse(...) method.
Maybe I missed something in your example, but I think you aren't trying
hard enough. :)

Precisely. I am not trying at all. I am coding between visits to Usenet.
This use case just popped up and was pretty simple (at first, before I
got to the reverse function) so I dropped it off. This is a wild macro,
not farm-bred, deliberately crafted to embarrass macro. A real live
natural comes up all the time working wouldn't want to code without it
macro. I could have searched my code base to find more brutal cases, but
this is short and sweet and unforced and uncontrived and wheres my
thesaurus?


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
 
?

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

Paul said:
>
> Oh come on, you have to count the parentheses too.

We could define hundreds of way how to count tokens.
But see the program as a tree:

nth
/ \
/ \
/ \
1+ list
| / | \
| / | \
truncate pos zero neg
|
|
signum
|
|
num

And I didn't count the indentation level and \n in Python code.
Why should I? They are editor commands.

> Anyway, token count doesn't mean much, you have to instead go by the
> user's cognitive effort in dealing with the prefix notation etc.,

How complicated ss it to say "cmp(a, b)" compared to "a cmp b"?
After a few days writing Lisp code your brain specializes on that
style. Arabian countries write from right to left. They seem to have
no problem to use what they know.
I admit that I am used to write +, -, * and / infix, because I were
trained in that thinking since day 1 in school.
In our example program there was only 1+ compared to ".. + 1" which
looks "alien" to untrained people.
If a program uses extensive math we can get syntax for Lisp that is
even more pleasant to read than Pythons:
17a + x³-x²


> which isn't purely a matter of token count. And if (+ 2 3) were
> really as easy to read as 2+3, mathematics would have been written
> that way all along.

Mathmaticians invented prefix notation and they use it regularily.
They inventey operators that wrap around their arguments, as one can
see here: http://www.mathe-trainer.com/formel/?SN=&t=1

Or think of indices, etc.



Yes, that works. And that's why I wanted to make it a macro.
Now you are essentially doing what I did in my first Lisp version.
While this works it is farer away from what we think.

(nif 0 "p" "z" "n")
(nif 0 #'p #'z #'n)
are exactly what one thinks.
For this reason "if" is implemented as a keyword in Python.
It allows you to give code as a block instead of embedding it into
a lambda or a def (which even needs a name).


And we might go further (again with an easy Graham example).
See this typical pattern:

result = timeConsumingCalculation()
if result:
use(result)

We need this ugly temporary variable result to refer to it.
If we could use the anaphor[1] "it" that could make situations like
these more clean.

Imagine Python would have an "anaphoric if", "aif". Then:

aif timeConsumingCalculation():
use(it)

Many Lispers might have this as a macro in their toolbox after some
time of coding or after reading Graham.
A short three-liner in Lisp and I can really say:

(aif (timeConsumingCalculation)
(use it))

How would you solve this in Python?
You could embed it inside a lambda and must somehow make the
variable "it" visible in it, because in the context of aif this
"it" gets bound to the result.


>
> There's a Haskell builtin called 'seq' which forces evaluation but
> again I'm not sure precisely how to apply it here.

I wouldn't wonder if there was an operator like "seq" to do that.
So in some languages that support functional programming one needs to do
extra work to get lazyness, while in Haskell one gets extra work if one
doesn't want it. But maybe someone can correct me here.
In Lisp one could build some features to get lazyness as well.


[1] http://en.wikipedia.org/wiki/Anaphora_(linguistics)

I hope this posting was not sent two times. I just sent it but it didn't
appear in my list after reloading.


André
--
 
P

philip.armitage

Paul said:
André Thieme <[email protected]> writes:
which isn't purely a matter of token count. And if (+ 2 3) were
really as easy to read as 2+3, mathematics would have been written
that way all along.

Maybe I am a "mutant" as Ken suggests but while mathematicians may
think in terms of infix, programmers have got very used to:

function (arg, arg, ...)

So when I see (+ 2 3) I just think function 'add' with arguments 2 and
3. Yep, I've moved the parens and removed the comma but that just makes
it even clearer. Then bring in more statement and you either have to
remember precedence rules (I can never remember those) or add some
parenthesis (oops!).

This may sounds paper thin to some people but if you appreciate
consistency then you'll appreciate the syntax.

Phil
 

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

Latest Threads

Top