merits of Lisp vs Python

P

Paddy

Jesús Carrete Montaña said:
Well, Python certainly is faster than most people doing floating-point
arithmetic by hand, but I don't think this is the correct argument to use
against Lisp :p.
Why not!
Lispers can indeed roll-their-own anything, many do it seems do just
that. But others look at the *time saving* libraries available to users
of Python and think hmm...
-Paddy.
 
H

hit_the_lights

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


It would be exactly like the example given, just "aref" replaced with
something else. An example implementation:

==========================================
(defgeneric $ (container key))
(defgeneric (setf $) (value container key))

;;; Implementation for arrays

(defmethod $ ((container array) (key integer))
(aref container key))

(defmethod (setf $) (value (container array) (key integer))
(setf (aref container key) value))
==========================================

And usage:

==========================================
CL-USER(3): (defparameter a (vector 1 2 3 4 5))
A
CL-USER(4): ($ a 0)
1
CL-USER(5): (setf ($ a 0) 9)
9
CL-USER(6): a
#(9 2 3 4 5)
==========================================

The nice thing is, that you *can* dispatch on the container,
the key and the value.
 
P

Paddy

Paul said:
Sure, connecting together programs and libraries that were written in other
languages is what a glue language is.


That's the thing, those modules are written in languages other than
Python because Python is not attractive for coding those functions
directly in Python. That is a real weakness of Python and glossing
over it by saying to write the functions in other languages and then
wrap them in the C API is not a very impressive answer. For example,
Lisp is routinely used for writing scientific and numerical code
directly with performance comparable to C or whatever. There is no
need to mess with wrapping modules written in other languages, an
operation which should not be trivialized.
You failed to see that Python accepts that useful work is out their,
already written, and some of it is not written in Python.
Would you say that All useful code is only written in Lisp? Or that all
future useful code will only be written in Lisp?
You could waste a lot of time re-writing what is already available, in
Lisp.

- Paddy.
 
K

Ken Tilton

Paul said:
Somehow it's something other than a rant if X is Lisp?

Ah, your discriminator misfired. Keep your eye on the bouncing rant:

I was not espousing any language, I was espousing matching the tool to
the task. That segued into my Lisp ball of mud rant, but, hell, even C
offers iteration along with recursion. That observation turns the rant
back on all-x-all-the-time languages, including I would note Steele's
constraint programming language, which at first used a constraint to do
variable assignment. Speaking of Cells...

:)

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
 
J

John Thingstad

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.

In lisp: (loop for a in y do (do-something a))

There is one difference.. There is no iterator so you have different
pronouns for each sequence type:

list: (loop for a in y ..
array: (loop for a across y ..
hash: (loop for a over y ..

hardly ideal, but workable.

Still it is a lot simpler to change the declaration in the start of the
loop
than having to changing the access to all references to a variable as you
might have to
with recursion. Consider

(defun func-iter (list)
(func (first list)))
(when (not (endp list))
(func-iter (rest list)))

(You could write (mapc #'(lambda (e) (func e)) list) but that is beside
the point.)

or something like that. What happens if you change the type to a array?
Total rewrite..
From a software engineering point of view iteration is preferable to
recursion because
maintenance and aggregation is simpler. (Sorry about the digression.)
 
P

Paddy

Seems like a trivial commonality between the languages, and a trivial
library, but that's not at all what I was laughing at...
Yep, doctest is trivial to use. Its part of its power ;-)
Actually, I don't care what you put into your library -- to some exent,
the more the merrier (as I've said elsewhere, I wish we had your
community of busy ... um ... beavers :) to create libraries full of
stuff, trivial or not!) The wheat will rise from the chaff. (Some
Lispers might disagree with me here.)
Its not so much the library creation. You also need the organisation,
and the willingness to accept that others can write good code too, (in
whatever language), and hold off from that first impulse to
roll-your-own library.
But anyway, what I was laughing at had nothing to do with doctest --
but that you use wikipedia to document your libraries. Elsewhere I have
aregued that Wikipedia is a stupid marketing document -- *many* Lispers
disagree with me here, so let's no go down this road, please as it's
soooooooo OT! So, I'm mostly laughing at the laughability of the
concept of the Wikipedia as somehow a source of all wisdom, not doctest
per se. Random ten-line Python libraries (as well as dead vaporware
python projects, as well as a whole bunch of other useless crap, and
the very occassionally useful crap) being in Wikiperdia just makes me
smile, that's all.
Oh, you don't like Wikipedia.
There are a lot of people that use Wikipedia. I think some of them
might want to learn to program. I make it easier for them to find
Python by helping to maintain Python within Wikipedia.
If I am researching anything then I like to cross check with
information from multiple sites. that's just good practice.
Some people dislike Wikipedia which is fine. Some people dislike
Wikipedia and deliberately sabotage it, which is vandalism.

-Paddy.
 
R

Robert Uhl

mystilleef said:
Any sizable Lisp applications will make extensive use of macros. Emacs
and magic ( the web framework) come to mind.

$ cat `find /usr/share/emacs/ -name '*.el' -print ` | grep defmacro | wc -l
1393
$ cat `find /usr/share/emacs/ -name '*.el' -print ` | grep defun | wc -l
29244

So it looks like there's one macro for every twenty-one functions. That
doesn't seem too extensive, nor too scarce.
My experience has shown that nobody but the person who writes the DSL
extension can maintain their code.

Emacs has been used for almost thirty years now, by tens (hundreds?) of
thousands of programmers, and extended by almost every one of them.
The benefits of extending a language in a domain specific manner are
exaggerated.

Certainly they seem useful to the authors of such packages as BBDB and
emacs-w3m.

--
Robert Uhl <http://public.xdi.org/=ruhl>
As a client for MS Exchange, MS Outlook is quite good. As an Internet
e-mail client [e.g, POP3/IMAP], it's roughly equivalent to strapping a
few pounds of plastique to your gonads and painting a day-glo orange
bulls-eye on your knickers. -- Morely Dotes in nan-ae
 
P

Paddy

John said:
In lisp: (loop for a in y do (do-something a))

There is one difference.. There is no iterator so you have different
pronouns for each sequence type:

list: (loop for a in y ..
array: (loop for a across y ..
hash: (loop for a over y ..

hardly ideal, but workable.

Still it is a lot simpler to change the declaration in the start of the
loop
than having to changing the access to all references to a variable as you
might have to
I can't quite figure out the meaning of your sentence above.
with recursion. Consider

(defun func-iter (list)
(func (first list)))
(when (not (endp list))
(func-iter (rest list)))

(You could write (mapc #'(lambda (e) (func e)) list) but that is beside
the point.)

or something like that. What happens if you change the type to a array?
Total rewrite..
Not even close.

In my example above:
for a in y:
dosomethingwith(a)
y could be a lot of built-in types such as an array, list, tuple, dict,
file, or set.

- Paddy.
 
R

Robert Uhl

Steven D'Aprano said:
Even if you're stuck on some god-forsaken Windows PC with just
Notepad, you can still read Python code.

Ummm...Lisp ain't APL--it's just ASCII (or ISO-8859-1 or Unicode or
whatever...), and thus just as readable in Notepad as anything else.
Now, *writing* Python code with Notepad isn't as easy, but it is still
doable. How about Lisp code?

Given that fellows were writing Lisp code before there were CRTs
(e.g. using teletypes to type), it's quite doable. Would I want to do
so? Of course not, no more than I'd want to write Python in Notepad.
The day has not yet arrived that nobody ever needs to edit code in a
plain, vanilla text editor.

My platform has emacs and vi by default. There are editors as
brain-damaged as Notepad, but I never use them, and in an emergency they
wouldn't run (as they require X).

Now, force me to write Lisp _or_ Python in ed and things will get very
ugly...
 
R

Robert Uhl

Steven D'Aprano said:
Such a pity that answer is, apparently, wrong.

Thank you to those who wrote back with the more accurate answer, which
apparently is "yes, it is easy and there are no error messages".

Yes, you can do it if you want--but you have to explicitly say that
you're doing so. In other words, it wouldn't happen by accident. And
due to the package system, package A doing it wouldn't infect package B
unless B allowed it to.

In other words, you have to put the bullet in the chamber, take off the
safety and point the gun at your foot.

--
Robert Uhl <http://public.xdi.org/=ruhl>
What some idiot in Glasgow or NYC, what a million idiots do, has nothing
at all to do with me, I can only be judged by the actions I take with my
possessions. To do anything else is to spit upon my existence as an
individual human. --R.D. Metcalf
 
R

Robert Uhl

I have the code here (probably not the latest bcs I left the company
when it was acquired), let's do a little experiment, for what it's
worth: 89727 lines of Lisp code in 131 modules (lisp code files), 3306
"(defun" (by grep|wc), and 261 "(defmacro". [We did NOT use macros as
functions!] [Note that lines of code doesn't really matter in Lisp.]

Wow--my emacs install has 1,152,598 lines of code in 1,570 files, 29,244
defuns and 1,393 defmacros. This really doesn't prove anything
whatsoever (as I imagine that your stuff was a _lot_ more complex),
except maybe how great the FSF is for giving away this sort of thing for
free.
 
M

Markus Triska

Ken Tilton said:
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.)

Don't expect to learn Prolog properly in so little time. To your
previous question whether the ~180 lines of Lisp code in some online
book constitute an "industrial strength" Prolog: only if the following
~180 lines of Prolog code implement an "industrial strength" Lisp.


ws --> [W], { W =< 0' }, ws.
ws --> [].

open_paren --> ws, "(", ws.
close_paren --> ws, ")", ws.

parse(String, Expr) :- phrase(expressions(Expr), String).

list(Es) --> open_paren, expressions(Es), close_paren.

expressions([E|Es]) -->
expression(E), ws,
!, % single solution: longest input match
expressions(Es).
expressions([]) --> [].

expression(symbol(A)) --> symbol(A0), { name(A, A0) }.
expression(number(N)) --> number(N0), { name(N, N0) }.
expression(List) --> list(List).
expression([symbol(quote),Q]) --> "'", expression(Q).

number([D|Ds]) --> digit(D), number(Ds).
number([D]) --> digit(D).

digit(D) --> [D], {0'0 =< D, D =< 0'9 }.

symbol([A|As]) -->
[A],
{ memberchk(A, "+/-*><=abcdefghijklmnopqrstuvwxyz") },
symbolr(As).

symbolr([A|As]) -->
[A],
{ memberchk(A, "+/-*><=abcdefghijklmnopqrstuvwxyz0123456789") },
symbolr(As).
symbolr([]) --> [].

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Interpretation
--------------
Declaratively, execution of a Lisp form establishes a relation
between the (function and variable) binding environment before its
execution and the environment after its execution. A Lisp program
is a sequence of Lisp forms, and its result is the sequence of
their results. Initially, the environment is empty.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

run(Program, Values) :-
parse(Program, Forms0),
empty_assoc(E),
compile_all(Forms0, Forms),
eval_all(Forms, E, _, E, _, Values).

fold([], _, V, V).
fold([F|Fs], Op, V0, V) :- E =.. [Op,V0,F], V1 is E, fold(Fs, Op, V1, V).

compile_all(Fs0, Fs) :- maplist(compile, Fs0, Fs).

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
compile/2 marks (with "user/1") calls of user-defined functions.
This eliminates an otherwise defaulty representation of function
calls and thus allows for first argument indexing in eval/7.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

compile(F0, F) :-
( F0 = number(_) -> F = F0
; F0 = symbol(t) -> F = t
; F0 = symbol(nil) -> F = nil
; F0 = symbol(_) -> F = F0
; F0 = [] -> F = []
; F0 = [symbol(quote)|Args] -> F = [quote|Args]
; F0 = [symbol(setq),symbol(Var),Val0] ->
compile(Val0, Val),
F = [setq,Var,Val]
; F0 = [symbol(Op)|Args0],
memberchk(Op, [+,-,*,equal,if,>,<,=,progn,eval,list,car,cons,
cdr,while,not]) ->
compile_all(Args0, Args),
F = [Op|Args]
; F0 = [symbol(defun),symbol(Name),Args0|Body0] ->
compile_all(Body0, Body),
maplist(un_symbol, Args0, Args),
F = [defun,Name,Args|Body]
; F0 = [symbol(Op)|Args0] ->
compile_all(Args0, Args),
F = [user(Op)|Args]
).

un_symbol(symbol(S), S).

eval_all([], Fs, Fs, Vs, Vs, []).
eval_all([A|As], Fs0, Fs, Vs0, Vs, [B|Bs]) :-
eval(A, Fs0, Fs1, Vs0, Vs1, B),
eval_all(As, Fs1, Fs, Vs1, Vs, Bs).

eval(number(N), Fs, Fs, Vs, Vs, N).
eval(t, Fs, Fs, Vs, Vs, t).
eval(nil, Fs, Fs, Vs, Vs, nil).
eval(symbol(A), Fs, Fs, Vs, Vs, V) :- get_assoc(A, Vs, V). % variable lookup
eval([L|Ls], Fs0, Fs, Vs0, Vs, Value) :- eval(L, Ls, Fs0, Fs, Vs0, Vs, Value).

eval(+, Args0, Fs0, Fs, Vs0, Vs, Value) :-
eval_all(Args0, Fs0, Fs, Vs0, Vs, Args),
fold(Args, (+), 0, Value).
eval(-, [V0|Rest], Fs0, Fs, Vs0, Vs, Value) :-
eval(V0, Fs0, Fs1, Vs0, Vs1, V1),
eval_all(Rest, Fs1, Fs, Vs1, Vs, Vals),
fold(Vals, (-), V1, Value).
eval(*, Args0, Fs0, Fs, Vs0, Vs, Value) :-
eval_all(Args0, Fs0, Fs, Vs0, Vs, Args),
fold(Args, (*), 1, Value).
eval(equal, [A0,B0], Fs0, Fs, Vs0, Vs, Value) :-
eval(A0, Fs0, Fs1, Vs0, Vs1, A),
eval(B0, Fs1, Fs, Vs1, Vs, B),
( A == B -> Value = t ; Value = nil ).
eval(if, [Cond,Then|Else], Fs0, Fs, Vs0, Vs, Value) :-
eval(Cond, Fs0, Fs1, Vs0, Vs1, V),
( V = nil ->
eval_all(Else, Fs1, Fs, Vs1, Vs, Values),
last(Values, Value)
; eval(Then, Fs1, Fs, Vs1, Vs, Value)
).
eval(not, [Arg], Fs0, Fs, Vs0, Vs, Value) :-
eval(Arg, Fs0, Fs, Vs0, Vs, V),
( V == nil -> Value = t ; Value = nil ).
eval(>, [Arg1,Arg2], Fs0, Fs, Vs0, Vs, Value) :-
eval(Arg1, Fs0, Fs1, Vs0, Vs1, V1),
eval(Arg2, Fs1, Fs, Vs1, Vs, V2),
( V1 > V2 -> Value = t ; Value = nil ).
eval(<, [Arg1,Arg2], Fs0, Fs, Vs0, Vs, Value) :-
eval(Arg1, Fs0, Fs1, Vs0, Vs1, V1),
eval(Arg2, Fs1, Fs, Vs1, Vs, V2),
( V1 < V2 -> Value = t ; Value = nil ).
eval(=, [Arg1,Arg2], Fs0, Fs, Vs0, Vs, Value) :-
eval(Arg1, Fs0, Fs1, Vs0, Vs1, V1),
eval(Arg2, Fs1, Fs, Vs1, Vs, V2),
( V1 =:= V2 -> Value = t ; Value = nil ).
eval(progn, Ps, Fs0, Fs, Vs0, Vs, Value) :-
eval_all(Ps, Fs0, Fs, Vs0, Vs, Values),
last(Values, Value).
eval(eval, [Form0], Fs0, Fs, Vs0, Vs, V) :-
eval(Form0, Fs0, Fs1, Vs0, Vs1, Form1),
compile(Form1, Form2),
eval(Form2, Fs1, Fs, Vs1, Vs, V).
eval(quote, [Q], Fs, Fs, Vs, Vs, Q).
eval(setq, [Var,V0], Fs0, Fs, Vs0, Vs, V) :-
eval(V0, Fs0, Fs, Vs0, Vs1, V),
put_assoc(Var, Vs1, V, Vs).
eval(defun, [Func,Args|Body], Fs0, Fs, Vs, Vs, Func) :-
put_assoc(Func, Fs0, Args-Body, Fs).
eval(list, Ls0, Fs0, Fs, Vs0, Vs, Ls) :-
eval_all(Ls0, Fs0, Fs, Vs0, Vs, Ls).
eval(cons, [Car0,Cdr0], Fs0, Fs, Vs0, Vs, [Car|Cdr]) :-
eval(Car0, Fs0, Fs1, Vs0, Vs1, Car),
eval(Cdr0, Fs1, Fs, Vs1, Vs, Cdr).
eval(car, [Ls0], Fs0, Fs, Vs0, Vs, Car) :-
eval(Ls0, Fs0, Fs, Vs0, Vs, [Car|_]).
eval(cdr, [Ls0], Fs0, Fs, Vs0, Vs, Cdr) :-
eval(Ls0, Fs0, Fs, Vs0, Vs, [_|Cdr]).
eval(while, [Cond|Body], Fs0, Fs, Vs0, Vs, Value) :-
eval(Cond, Fs0, Fs1, Vs0, Vs1, V),
( V == nil -> Value = nil, Fs = Fs0, Vs = Vs0
; eval_all(Body, Fs1, Fs2, Vs1, Vs2, _),
eval(while, [Cond|Body], Fs2, Fs, Vs2, Vs, Value)
).
eval(user(F), Args0, Fs0, Fs, Vs0, Vs, Value) :-
eval_all(Args0, Fs0, Fs, Vs0, Vs, Args),
get_assoc(F, Fs, As-Body),
empty_assoc(E),
bind_arguments(As, Args, E, Bindings),
eval_all(Body, Fs, _, Bindings, _, Results),
last(Results, Value).

bind_arguments([], [], Bs, Bs).
bind_arguments([A|As], [V|Vs], Bs0, Bs) :-
put_assoc(A, Bs0, V, Bs1),
bind_arguments(As, Vs, Bs1, Bs).


They give you a simple Lisp and, in contrast to some online books
claiming to give you "Prolog" (an ISO-standardised language) and then
failing to even parse a single proper Prolog term, also let you write
it in its natural form. Example queries tested with SWI Prolog:

"append":

?- run("(defun append (x y) (if (equal x '()) y (cons (car x) (append (cdr x) y)))) (append '(1 2 3) '(4 5))", V).

==> V = [append, [number(1), number(2), number(3), number(4), number(5)]] ;


Fibonacci, naive version:

?- time(run("(defun fib (n) (if (= 0 n) 0 (if (= 1 n) 1 (+ (fib (- n 1)) (fib (- n 2)))))) (fib 24)", V)).

==> V = [fib, 46368] ;
9,567,271 inferences, 3.42 CPU in 3.50 seconds (98% CPU, 2797448 Lips)

Different version:

?- time(run("(defun fib (n) (if (= 0 n) 0 (fib1 0 1 1 n))) (defun fib1 (f1 f2 i to) (if (= i to) f2 (fib1 f2 (+ f1 f2) (+ i 1) to))) (fib 100)", V)).

==> 16,275 inferences, 0.01 CPU in 0.01 seconds (163% CPU, 1627500 Lips)
V = [fib, fib1, 354224848179261915075] ;


Using a while loop:

?- time((run("(defun fib (n) (setq f (cons 0 1)) (setq i 0) (while (< i n) (setq f (cons (cdr f) (+ (car f) (cdr f)))) (setq i (+ i 1))) (car f)) (fib 200)", V))).

==> 20,509 inferences, 0.02 CPU in 0.01 seconds (239% CPU, 1025450 Lips)
V = [fib, 280571172992510140037611932413038677189525] ;


Showing "eval" and "map":


?- run("(defun map (f xs) (if (equal xs '()) '() (cons (eval (list f (car xs))) (map f (cdr xs))))) (defun plus1 (x) (+ 1 x)) (map 'plus1 '(1 2 3))", Vs).

==> Vs = [map, plus1, [2, 3, 4]] ;


Prolog's analogon to Lisp's macros is term_expansion/2 by the way.


All the best!
Markus Triska
 
G

greg

Juan said:
I see no dinamism on your example, just static overloading.

There's nothing static about it:

q = raw_input()
if q == "A":
a = 1
b = 2
else:
a = "x"
b = "y"
c = a + b

There is no way that the compiler can statically
determine what the + operator needs to do here.
 
G

greg

Espen said:
That's what I call /kludgy/, not /dynamic/ ;-)

I think "kludgy" is a bit unfair, since this is a
result of doing things in a very simple and uniform
way -- rather a Lispy concept, I would have thought. :)
 
G

greg

Paul said:
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--

Indeed, Python has sometimes been described
as "pathologically dynamic". All that dynamism
is handy sometimes, but it does get in the
way of improving efficiency.

Often discussions take place on python-dev
about ways to selectively limit the dynamism
to make some optimisation possible.
 
G

greg

Jon said:
Outside Lisp, macros are for syntax. Evaluation semantics (e.g. lazy
evaluation) then have nothing to do with macros.

I don't think that's entirely true. With currying
and lazy evaluation, there's a sense in which
Haskell function definitions already *are* macros.

There are limits to the degree of syntactical
transformation you can reasonably achieve -- it
wouldn't be easy to make Haskell code look exactly
like Cobol, for example. But usually that's not
what you're after -- rather you just want to
devise some way to express your intent with a
minimum of boilerplate.

I once implemented a parser in HUGS. Using nothing
but built-in language features, I was able to
construct a system whereby I could more or less
just write down the BNF grammar rules and feed them
straight into the HUGS compiler. Achieving a
similar trick in Lisp would probably have required
using macros.
 
G

greg

Robert said:
o Symbols

In Lisp, a symbol is essentially a hashed string;

Are you aware that strings can be interned in Python?
Furthermore, any string literal in the source that
is a syntactically valid identifier is automatically
interned, and you can intern any string explicitly
if you need. This gives you exactly the same
capabilities as symbols in Lisp.

For example, due to the automatic interning, the
string comparison in the following is just a pointer
comparison:

fred = 'hello'
if fred == 'hello':
print 'Greetings'
 
R

Robert Uhl

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.

GUIs are a weak point, or were last I looked. There are at least three
GTK+ interfaces.

Database access is handled very nicely with CLSQL, which does OR mapping
right.

I've not written code to 'consume web-services,' but I daresay that
NET.HTML.CLIENT (believe that's the name) would do the trick.

--
Robert Uhl <http://public.xdi.org/=ruhl>
If anybody can show me in the Bible the command, 'Thou shalt not smoke,'
I am ready to keep it; but I haven't found it yet. I find ten
commandments, and it's as much as I can do to keep them; and I've no
desire to make them into eleven or twelve. --C. H. Spurgeon
 
G

greg

George said:
I'm sure there should be more convincing examples for macros, but
neither this nor the 'unless' syntax sugar cuts it.

Also, the new 'with' statement and associated
protocol covers much of the ground that was left
out by the existing constructs.
 
K

Ken Tilton

Markus said:
Don't expect to learn Prolog properly in so little time.

Lawdy, no, but I had all those Art of Prolog and Craft of Prolog and a
couple other books and I was staring at pages of intense code just
trying to do basic stuff. I had not learned prolog, but I could see the
masters writing hairy code to basic stuff so I concluded...run away! run
away! :)

I think the other thing that got me was cuts, which I translated as "did
we say unification all the time? sorry..." :)

To your
previous question whether the ~180 lines of Lisp code in some online
book constitute an "industrial strength" Prolog: only if the following
~180 lines of Prolog code implement an "industrial strength" Lisp.

<snip lisp-in-Prolog>

Way cool.

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
 

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