From: Chris Capel
Subject: Lisp readability
Date: 
Message-ID: <10ifj41m62tfi7f@corp.supernews.com>
Lisp is really readable.

At least, that's my impression, after having a few months minor experience
with the language.  It sort of surprised me--very pleasantly--to find out
the difference between grokking Lisp code and grokking Visual Basic code. 
(I have, unfortunately, been put into that position.)  When I first started
to use Lisp, I was surprised at the lack of documentation in most of the
free libraries.  (Edi's are a notable exception.)  Granted, they are less
mature than the equivalent C or Perl or even PHP libraries, but I found
that I didn't really *need* documentation to be able to use them.  The code
itself told me how to use it.  It's the first time in my life I've not been
afraid to read others' source code.

So I'm wondering.  Why isn't this touted more as an advantage of Lisp? 
Perhaps my experience is unusual?  Perhaps those familiar with Lisp more
often come from backgrounds of other HLLs that provide readability more
comparable to Lisp than VB or even C# is.  Perhaps I just deal a lot with
poorly written code.  But for all this nashing of teeth over parenthesis,
I'm surprised that more people don't make the point that in the long run,
it's much easier to read others' Lisp code than it is to read their java
code.

Chris Capel

From: Paul F. Dietz
Subject: Re: Lisp readability
Date: 
Message-ID: <t42dnWhrupC5SrrcRVn-vA@dls.net>
Chris Capel wrote:

> So I'm wondering.  Why isn't this touted more as an advantage of Lisp? 

Because people don't believe it, unless they've had your experience,
in which case they don't need to be told?

	Paul
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87isbbiwo2.fsf@david-steuber.com>
"Paul F. Dietz" <·····@dls.net> writes:

> Chris Capel wrote:
> 
> > So I'm wondering.  Why isn't this touted more as an advantage of
> > Lisp?
> 
> Because people don't believe it, unless they've had your experience,
> in which case they don't need to be told?

Perhaps.  Or perhaps it is called code for a reason :-p

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Alex Mizrahi
Subject: Re: Lisp readability
Date: 
Message-ID: <2oq4vdFd0mqvU1@uni-berlin.de>
(message (Hello 'Chris)
(you :wrote  :on '(Sat, 21 Aug 2004 17:26:23 -0500))
(

 CC> Lisp is really readable.

 CC> Perhaps my experience is unusual?

i have same experience.
i have much more experience in c++, [object] pascal, basic and PHP than in
lisp, however lisp code appears to be definitely more
readable/understandable.

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
(prin1 "Jane dates only Lisp programmers"))
From: Jeff
Subject: Re: Lisp readability
Date: 
Message-ID: <f6VVc.51449$mD.46262@attbi_s02>
Alex Mizrahi wrote:

> (message (Hello 'Chris)
> (you :wrote  :on '(Sat, 21 Aug 2004 17:26:23 -0500))
> (
> 
>  CC> Lisp is really readable.
>  CC> Perhaps my experience is unusual?
> 

Before I really sat down and decided to actually learn Common Lisp, I
found it very unreadable. After learning it, I, too, find it much more
readable than *most* other languages.

I think parentheses are what is pointed to by non-Lisp programmers
simply because they are what is most noticeable. However, while I was
in my "intermediate" phase of Common Lisp (which I feel I'm barely
coming out of) What I found most unreadable were the inconsistencies
that macros added to the language.

Because things can be done in so many different ways in Common Lisp,
and since macros play a large role in that, one really needs to become
accustomed to each portion of Common Lisp before it really starts to
become readable.

For example, given the following prototype to work with:

(FOO-BAR function)

Should this be called in which way?

(FOO-BAR +)
(FOO-BAR '+)
(FOO-BAR #'+)

It really depends on whether or not FOO-BAR is a macro or not, and how
it is implemented inside. Many Lisp libraries are difficult to get used
to because of this. Most of the time, I still find myself just having
to memorize which functions take which kinds of parameters. Perhaps
some of the more experienced Lispers here can shed some light on the
dark alley (are there some unspoken rules that I'm just not aware of)?

Jeff
From: neo88
Subject: Re: Lisp readability
Date: 
Message-ID: <6a73bb68.0408220457.6cff05fb@posting.google.com>
> I think parentheses are what is pointed to by non-Lisp programmers
> simply because they are what is most noticeable. However, while I was
> in my "intermediate" phase of Common Lisp (which I feel I'm barely
> coming out of) What I found most unreadable were the inconsistencies
> that macros added to the language.

I agree. I had a hard time when first starting out remembering to do
stuff like:

(defun foo (args)
  (cond (args null) nil) 
        (t (do_stuff_with_args_here))))

I always found myself wanting to do something more like:

(defun foo args
  (cond (args) null nil)
        (t do_stuff))

Is this unusual? Anyways, it didn't take me to long to figure out how
to place the arguments to functions etc in parentheses. I think Lisp
is readable mainly because it emphisizes on clarity rather then
brevity. For instance in C++ I might be tempted to do something like:

class foo {
  private:
    int x;
    int y;
  public:
    long do_x;
    char do_y;
}

whereas in Lisp

(defclass foo ()
  ((foo-stuff :accessor bar
              :initform 'me
              :initarg :foo-stuff)))

Maybe these aren't the greatest examples, but my point is that Lisp is
(to me) much clearer than C++. If the examples didn't have "foo" and
such in them maybe it would be more clear. I always found myself
trying to type the shortest possible variable and class names in C++.
My code was cluttered with x's and y's, now it's not. I also think
that CLOS is the best OO system I have seen. It really helps you grasp
the concepts of OO a lot faster than C++ or Java does. I also find it
hard to believe I am saying this since just a few short months ago, I
hailed C++ as the ultimate language. :-P
 
> Because things can be done in so many different ways in Common Lisp,
> and since macros play a large role in that, one really needs to become
> accustomed to each portion of Common Lisp before it really starts to
> become readable.

Sounds like something someone would say about Perl.
 
> For example, given the following prototype to work with:
> 
> (FOO-BAR function)
> 
> Should this be called in which way?
> 
> (FOO-BAR +)
> (FOO-BAR '+)
> (FOO-BAR #'+)

It can be called either of those ways. All #'+ does is create a lambda
list, that shouldn't matter to your macro.
 
> It really depends on whether or not FOO-BAR is a macro or not, and how
> it is implemented inside. Many Lisp libraries are difficult to get used
> to because of this. Most of the time, I still find myself just having
> to memorize which functions take which kinds of parameters. Perhaps
> some of the more experienced Lispers here can shed some light on the
> dark alley (are there some unspoken rules that I'm just not aware of)?
> 
> Jeff

Well, you're probably more experianced then me, so I don't know if
this will help, but you don't really need to know how a macro does
what it does, just that it does in fact do what it does. So you can
call it any variety of ways, with lambda lists etc, and it should
work. At least that's what I always thought....

-- 
May the Source be with you.
neo88 (Philip Haddad)
From: Joost Kremers
Subject: Re: Lisp readability
Date: 
Message-ID: <slrncih6rk.j0m.joostkremers@j.kremers4.news.arnhem.chello.nl>
neo88 wrote:
>> For example, given the following prototype to work with:
>> 
>> (FOO-BAR function)
>> 
>> Should this be called in which way?
>> 
>> (FOO-BAR +)
>> (FOO-BAR '+)
>> (FOO-BAR #'+)
>
> It can be called either of those ways. All #'+ does is create a lambda
> list, that shouldn't matter to your macro.

the first one is definitely different, because lisp will interpret the
symbol + as a variable. so unless this variable is bound to something, lisp
will complain.

(well, in fact, the symbol + has a standard value as a variable, referring
to the last expression entered at the top-level. that's not what FOO-BAR
here wants, though.)

-- 
Joost Kremers                                      ············@yahoo.com
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
From: Jeff
Subject: Re: Lisp readability
Date: 
Message-ID: <X51Wc.166745$8_6.88815@attbi_s04>
Joost Kremers wrote:

> neo88 wrote:
> >> For example, given the following prototype to work with:
> >> 
> >> (FOO-BAR function)
> >> 
> >> Should this be called in which way?
> >> 
> >> (FOO-BAR +)
> >> (FOO-BAR '+)
> >> (FOO-BAR #'+)
> > 
> > It can be called either of those ways. All #'+ does is create a
> > lambda list, that shouldn't matter to your macro.
> 
> the first one is definitely different, because lisp will interpret the
> symbol + as a variable. so unless this variable is bound to
> something, lisp will complain.

Not necessarily. Consider the following implementation of FOO-BAR,

(defmacro FOO-BAR (f)
  `(,f 1 2 3))

Now, (FOO-BAR +) works just fine and is used exactly as the prototype
specified. The second is how I typically see callbacks declared (in
LispWorks, which is what I'm using). The last one (using #') is what I
would /expect/ to be correct, though.

> (well, in fact, the symbol + has a standard value as a variable,
> referring to the last expression entered at the top-level. that's not
> what FOO-BAR here wants, though.)

I think you mean * here (well, Corman Lisp and LispWorks both use * for
this meaning, and I don't know if other implementations use a different
symbol).

Jeff
From: Joost Kremers
Subject: Re: Lisp readability
Date: 
Message-ID: <slrncih873.j0m.joostkremers@j.kremers4.news.arnhem.chello.nl>
Jeff wrote:
>> the first one is definitely different, because lisp will interpret the
>> symbol + as a variable. so unless this variable is bound to
>> something, lisp will complain.
>
> Not necessarily. Consider the following implementation of FOO-BAR,
>
> (defmacro FOO-BAR (f)
>   `(,f 1 2 3))

oops, you're right. forgot that a macro call *doesn't* evaluate its
arguments. that's a big F there for me... ;-)

>> (well, in fact, the symbol + has a standard value as a variable,
>> referring to the last expression entered at the top-level. that's not
>> what FOO-BAR here wants, though.)
>
> I think you mean * here (well, Corman Lisp and LispWorks both use * for
> this meaning, and I don't know if other implementations use a different
> symbol).

AFAIK this is simply part of the standard. * refers to the (first) value
returned by the last expression entered at the top level, while + refers to
the expression itself.

-- 
Joost Kremers                                      ············@yahoo.com
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
From: Thomas Schilling
Subject: Re: Lisp readability
Date: 
Message-ID: <opsc4yzovhtrs3c0@news.CIS.DFN.DE>
Joost Kremers wrote:

> oops, you're right. forgot that a macro call *doesn't* evaluate its
> arguments. that's a big F there for me... ;-)

Well some macros do. It always depends on the implementation. (E.g. AND, 
OR evaluate everything.) Hence you should always document what parameters 
of your macro are evaluated.

-- 
      ,,
     \../   /  <<< The LISP Effect
    |_\\ _==__
__ | |bb|   | _________________________________________________
From: Hannah Schroeter
Subject: Re: Lisp readability
Date: 
Message-ID: <cga9fo$2rs$1@c3po.use.schlund.de>
Hello!

Thomas Schilling  <······@yahoo.de> wrote:
>Joost Kremers wrote:

>> oops, you're right. forgot that a macro call *doesn't* evaluate its
>> arguments. that's a big F there for me... ;-)

>Well some macros do. It always depends on the implementation. (E.g. AND, 
>OR evaluate everything.) Hence you should always document what parameters 
>of your macro are evaluated.

No, AND and OR do NOT necessarily evaluate everything.

Try for example

  (or 1 (/ 1 0))

Kind regards,

Hannah.
From: Joost Kremers
Subject: Re: Lisp readability
Date: 
Message-ID: <slrncihc6l.j0m.joostkremers@j.kremers4.news.arnhem.chello.nl>
Thomas Schilling wrote:
> Joost Kremers wrote:
>> oops, you're right. forgot that a macro call *doesn't* evaluate its
>> arguments. that's a big F there for me... ;-)
>
> Well some macros do.

well, in the case of a function, the arguments get evaluated *before* the
function itself gets executed, right? with a macro, this is clearly not the
case. that's what i meant when i said that a macro call doesn't evaluate
the arguments. the macro itself may, of course, but the call itself
doesn't.

-- 
Joost Kremers                                      ············@yahoo.com
Selbst in die Unterwelt dringt durch Spalten Licht
EN:SiS(9)
From: Thomas Schilling
Subject: Re: Lisp readability
Date: 
Message-ID: <opsc4zq209trs3c0@news.CIS.DFN.DE>
I claimed this nonsense:

> Well some macros do. It always depends on the implementation. (E.g. AND, 
> OR evaluate everything.)
      ^^^^^^^^^^^^^^^^^^^
Er, I meant: depending on the context (ie. arguments) it they evaluete 
just one argument up to everything. (BTW would a macro that always 
evaluates everything be always equivalent to a function? I guess it would, 
wouldn't it? ... Hm, I mean if it's written decently and doesn't change 
the order of evaluation.)
From: Vassil Nikolov
Subject: Re: Lisp readability
Date: 
Message-ID: <lzoel2trfo.fsf@janus.vassil.nikolov.names>
Thomas Schilling <······@yahoo.de> writes:

> [...]
> (BTW would a macro that always
> evaluates everything be always equivalent to a function? I guess it
> would, wouldn't it? ... Hm, I mean if it's written decently and
> doesn't change the order of evaluation.)


  Not quite equivalent---there are (at least) two differences:

  * can't funcall/apply a macro;

  * a macro (in certain cases) provides a setf place "for free".

  For example:

  (defun 1st-f (x) (first x))
  (defmacro 1st-m (x) `(first ,x))

  (funcall #'1st-f '(foo)) is OK
  (funcall #'1st-m '(foo)) is in error

  (setf (1st-f list) 'foo) needs a DEFSETF definition first
  (setf (1st-m list) 'foo) is OK


  ---Vassil.


-- 
Vassil Nikolov <········@poboxes.com>

Hollerith's Law of Docstrings: Everything can be summarized in 72 bytes.
From: Ray Dillinger
Subject: Re: Lisp readability
Date: 
Message-ID: <VOyWc.9290$54.136161@typhoon.sonic.net>
Thomas Schilling wrote:
 >(BTW would a macro that always
> evaluates everything be always equivalent to a function? I guess it 
> would, wouldn't it? ... Hm, I mean if it's written decently and doesn't 
> change the order of evaluation.)

Hmmmm.

Not exactly.  To be equivalent to functions, they'd need some other 
function properties: you'd be able to store them in data structures,
apply them, pass them as arguments or function results, etc.

It's interesting to think about though, isn't it?  Let's say that
there was a primitive-syntax "mu" that worked just like lambda except
that the procedures it created took unevaluated arguments.  You'd
also need a primitive-syntax "dyn-eval" that evaluated expressions
in the dynamic environment (ie, the environment inherited through
the chain of callers rather than the environment visible lexically
from the definition point).

This would allow you to implement first-class functions that do (I
think) just about everything that macros do now.  Debugging them
might be really irritating, because of the interaction of different
scoping disciplines when someone passes a lexically-inherited
variable (or an expression containing them) to a mu function.  Most
of the common cases would work if dyn-eval took dynamic inheritance
back to the most recent call-frame allocated for a lambda function
(as opposed to a mu function) and no further, seeing the complete
lexically-inherited environment available at this base frame and
caller environments only for variables bound in mu function frames.
But in some cases that might not be enough.

If not for the need to distinguish lambda-function and mu-function
call frames, I think you might be able to then implement lambda (or
a subtle variation of it in which it's the called procedure that
evaluates the arguments rather than the call itself) in terms
of mu and dyn-eval.  Unfortunately, I think it would probably
be dog slow.

Here's a mu-function implementation of "and" In schemish syntax,
assuming dyn-eval sees bindings in all calling frames back to the
most recent lambda-function frame, and the full lexically-inherited
environment visible at that point.  I'm going to leave the possibility
of implementing "lambda" to someone a bit more ambitious.

(define and
    (mu args
    (if (null? args) #t
        (let ((current (dyn-eval (car args)))
             (if current current
                 (and (cdr args))


				Bear
From: Ray Dillinger
Subject: Re: Lisp readability
Date: 
Message-ID: <ygIWc.9340$54.137698@typhoon.sonic.net>
Ray Dillinger wrote:

> It's interesting to think about though, isn't it?  Let's say that
> there was a primitive-syntax "mu" that worked just like lambda except
> that the procedures it created took unevaluated arguments.  

Actually one more thing would sort most of the problems out:
Both Mu and Lambda would be binding constructs that establish
a set of bindings in a given region.  The question is what to
do with references to variables not defined by that set of
bindings. In both cases, you'd follow the scope pointer to
a "parent" environment.  But in a lambda function the scope
pointer ought to be to the binding structure most closely
enclosing the binding structure being established (lexical)
and in a mu function the scope pointer ought to be to the
binding structure most closely enclosing the call site
(dynamic).

This would give an unambiguous and useful "chain" of
binding constructs, leading ultimately back to the top-level
environment, to both types of functions, allowing the lexical
scopes of lambda functions to be inherited by the mu functions
they call.  That would eliminate the need for dyn-eval, and
I think that it would do so with no loss of expressiveness.

So the mu-function definition of "and" would get simpler:

  (define and
     (mu args
     (if (null? args) #t
         (let ((current (eval (car args)))
              (if current current
                  (and (cdr args))

Neither of these (lambda or mu) is quite exactly the
lambda-calculus lambda; each is that lambda plus some
additional scope rules that make it more convenient
to write programs with.  You could make a third construct
where a bit indicating the status of the scope pointer
was given explicitly, and implement both lambda and mu
in terms of that; but it would itself be the same kind
of "shadow" against the lambda-calculus lambda.

                  Bear
From: Coby Beck
Subject: Re: Lisp readability
Date: 
Message-ID: <Tp3Wc.46838$fz2.38713@edtnps89>
"Jeff" <···@nospam.insightbb.com> wrote in message
···························@attbi_s04...
> Joost Kremers wrote:
> > (well, in fact, the symbol + has a standard value as a variable,
> > referring to the last expression entered at the top-level. that's not
> > what FOO-BAR here wants, though.)
>
> I think you mean * here (well, Corman Lisp and LispWorks both use * for
> this meaning, and I don't know if other implementations use a different
> symbol).

* ** *** + ++ +++ are all distinct and all part of the standard:

CL-USER 24 > (defvar *x* 4)
*X*
CL-USER 25 > (1+ *x*)
5
CL-USER 26 > (* *x* *x*)
16
CL-USER 27 > (values (list +++ '==> ***)
                     (list ++ '==> **)
                     (list + '==> *))
((DEFVAR *X* 4) ==> *X*)
((1+ *X*)       ==>   5)
((* *X* *X*)    ==>  16)

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: neo88
Subject: Re: Lisp readability
Date: 
Message-ID: <6a73bb68.0408221353.31280e70@posting.google.com>
> 
> (defun foo (args)
>   (cond (args null) nil) 
>         (t (do_stuff_with_args_here))))
> 

Oops. Quick fix to that above example:

(defun foo (args)
  (cond ((args null) nil)
         (t (do_stuff_with_args_here))))

:-)

-- 
May the Source be with you.
neo88 (Philip Haddad)
From: Rob Warnock
Subject: Re: Lisp readability
Date: 
Message-ID: <LqednaQOW8FDkLbcRVn-vw@speakeasy.net>
neo88 <······@truevine.net> wrote:
+---------------
| (defun foo (args)
|   (cond ((args null) nil)
|          (t (do_stuff_with_args_here))))
+---------------

Personally, I almost always go with the alternate COND style which
costs an extra vertical line but is (IMHO) *much* easier to read:

  (defun foo (args)
    (cond
      ((args null) nil)
      (t (do_stuff_with_args_here))))

Then if the consequence clauses get long, the even longer style
of only the test on the first line of the clause, despite the fact
that some of the clauses are short:

  (defun foo (args)
    (cond
      ((args null)
       nil)
      (t
       (do_stuff_with_args_here)
       (do_more_stuff_with_args_here)
       (and_more_stuff)
       (and_more)
       (and_some more))))

But I never (well, seldom!) mix those two styles in a single COND.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: neo88
Subject: Re: Lisp readability
Date: 
Message-ID: <6a73bb68.0408240646.3a09ef65@posting.google.com>
····@rpw3.org (Rob Warnock) wrote in message news:<······················@speakeasy.net>...
> neo88 <······@truevine.net> wrote:
> +---------------
> | (defun foo (args)
> |   (cond ((args null) nil)
> |          (t (do_stuff_with_args_here))))
> +---------------
> 
> Personally, I almost always go with the alternate COND style which
> costs an extra vertical line but is (IMHO) *much* easier to read:
> 
>   (defun foo (args)
>     (cond
>       ((args null) nil)
>       (t (do_stuff_with_args_here))))
> 
> Then if the consequence clauses get long, the even longer style
> of only the test on the first line of the clause, despite the fact
> that some of the clauses are short:
> 
>   (defun foo (args)
>     (cond
>       ((args null)
>        nil)
>       (t
>        (do_stuff_with_args_here)
>        (do_more_stuff_with_args_here)
>        (and_more_stuff)
>        (and_more)
>        (and_some more))))

I have never seen a COND statement written like that before. I guess
it's just my style that I was taught to just stick the atencedent and
terminating condtion on the same line. Because of this I don't find
your style MUCH easier to read.
 
> But I never (well, seldom!) mix those two styles in a single COND.
> 
> 
> -Rob
> 
> -----
> Rob Warnock			<····@rpw3.org>
> 627 26th Avenue			<URL:http://rpw3.org/>
> San Mateo, CA 94403		(650)572-2607

-- 
May the Source be with you.
neo88 (Philip Haddad)
From: Pascal Costanza
Subject: Re: Lisp readability
Date: 
Message-ID: <cgacjb$h8i$1@newsreader2.netcologne.de>
neo88 wrote:

> It can be called either of those ways. All #'+ does is create a lambda
> list, that shouldn't matter to your macro.

Just a note: It's clear what you mean from the context, but you are 
using the wrong terminology here.

- #'+ doesn't create anything. It returns the function that is 
associated with + in the current lexical scope. In this case, it's 
usually the function associated with the + symbol in the common-lisp 
package.

- #'(lambda (...) ...) creates a closure - a function whose free 
variables close over the lexical environment (unless they are special). 
The difference between #'+ and #'(lambda (...) ...) is that the former 
is passed a symbol whereas the latter is passed a lambda expression.

- A lambda list is the list of formal arguments defined for some 
function, macro, or similar definitions. Especially, it is not the 
lambda expression. See the following example.

(lambda (x y z) (+ x y z))
+------------------------+ <- lambda expression
         +-----+            <- lambda list

This terminology is probably a historical accident, but is used 
throughout the ANSI specification, so in the context of discussions 
about Common Lisp, it's important to stick to it in order to avoid 
confusion. (See 3.4 in the HyperSpec, and the Glossary.)


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: neo88
Subject: Re: Lisp readability
Date: 
Message-ID: <6a73bb68.0408221357.46ecab27@posting.google.com>
Pascal Costanza <········@web.de> wrote in message news:<············@newsreader2.netcologne.de>...
> neo88 wrote:
> 
> > It can be called either of those ways. All #'+ does is create a lambda
> > list, that shouldn't matter to your macro.
> 
> Just a note: It's clear what you mean from the context, but you are 
> using the wrong terminology here.
> 
> - #'+ doesn't create anything. It returns the function that is 
> associated with + in the current lexical scope. In this case, it's 
> usually the function associated with the + symbol in the common-lisp 
> package.
> 
> - #'(lambda (...) ...) creates a closure - a function whose free 
> variables close over the lexical environment (unless they are special). 
> The difference between #'+ and #'(lambda (...) ...) is that the former 
> is passed a symbol whereas the latter is passed a lambda expression.
> 
> - A lambda list is the list of formal arguments defined for some 
> function, macro, or similar definitions. Especially, it is not the 
> lambda expression. See the following example.
> 
> (lambda (x y z) (+ x y z))
> +------------------------+ <- lambda expression
>          +-----+            <- lambda list
> 
> This terminology is probably a historical accident, but is used 
> throughout the ANSI specification, so in the context of discussions 
> about Common Lisp, it's important to stick to it in order to avoid 
> confusion. (See 3.4 in the HyperSpec, and the Glossary.)
> 
> 
> Pascal

Thanks, that clears up some confusion I had as well. I wasn't 100%
sure what a lambda list was I guess. I will remember that.

-- 
May the Source be with you.
neo88 (Philip Haddad)
From: Doug Philips
Subject: Re: Lisp readability
Date: 
Message-ID: <0001HW.BD4E4ED20012AC9DF04075B0@news.nauticom.net>
On Sun, 22 Aug 2004 06:43:20 -0400, Stefan Ram wrote
(in article <··························@ram.dialup.fu-berlin.de>):

> "Jeff" <···@nospam.insightbb.com> writes:
>> I think parentheses are what is pointed to by non-Lisp programmers
>> simply because they are what is most noticeable.
> 
>   To me, it is irregularity of indentation.
> 
>   I have a hard time reading the following code by Frank Buss.
>   (This style could be used by many other authors of this group,
>   and I am just using his, because I already have used it before
>   for that purpose.)

[example elided.]

>   When I want to read this, the first thing I do, is to reformat
>   it, so that /every level/ of nesting indents by /the same
>   number/ of two positions:

[example edided.]

>   Frank already has kindly explained to me his reasons for his
>   indentation, so there is no need to repeat that here. Still,
>   I prefer a regular indentation.

Neither of those is easily readable by me, but Buss' style
is closer to my own idiosyncratic style than your style is.

Of course, being lisp, it is particularly easy to write your own
pretty printer so that you can see the code the way that is
easiest for you to read.

Although, what ultimately makes that code unreadable is not the
style of indentation or the placement of spaces, but that there is just
too much going on "in one place" in the first place.

<D\'gou
From: Frank Buss
Subject: Re: Lisp readability
Date: 
Message-ID: <cgar24$9ua$1@newsreader2.netcologne.de>
Doug Philips <····@mac.com> wrote:

> Although, what ultimately makes that code unreadable is not the
> style of indentation or the placement of spaces, but that there is just
> too much going on "in one place" in the first place.

Yes, you are right. Currently I'm reading "On Lisp" and I start to 
understand the bottom-up concept. You build your own language with low-
level functions and macros, and use this in higher-level functions until 
you have your program. Of course, somtimes you have to go down again, 
doing some refactoring, but this is easy with the interactive Lisp 
environment.

If you design carefully the building blocks, you can reuse it for 
different tasks. Indention is not so important for readability, as long 
as the functions are short and doing only one thing, if possible without 
side-effects. Another version of the mandelbrot program:

(defconstant *max-iteration* 93)

(defun escaped (z)
  (> (+ (* (realpart z) (realpart z))
        (* (imagpart z) (imagpart z)))
     4))

(defun calculate-iteration (c)
  (do ((z c (+ (* z z) c))
       (iteration 0 (1+ iteration)))
      ((or (>= iteration *max-iteration*)
           (escaped z))
       (return iteration))))

(defun mandelbrot (next-pixel new-line)
  (loop for y from -1 to 1.1 by 0.1 do
        (loop for x from -2 to 1 by 0.04 do
              (funcall next-pixel (calculate-iteration (complex x y))))
        (funcall new-line)))

(defun iteration-to-char (i)
  (code-char (- *max-iteration* i -32)))

(mandelbrot
 (lambda (i) (princ (iteration-to-char i)))
 #'terpri)


-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87llg665yf.fsf@david-steuber.com>
My version of the Mandelbrot program is a hack in progress.  It
duplicates most of the functionality of a version I had in C and Perl
a while back to create a movie.  It also has some additional
functionality like producing a TIFF file.  That code fails on CLisp
though because CLisp does not like to FILE-POSITION past the end of a
file.

My code is also currently dog slow.  It needs cleaning up for both
performance and readability.  If you are interested in looking at it,
it can be found here:

  http://www.david-steuber.com/~david/Lisp/fractal.lisp.txt

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: neo88
Subject: Re: Lisp readability
Date: 
Message-ID: <6a73bb68.0408230407.4339e94b@posting.google.com>
> My code is also currently dog slow.  It needs cleaning up for both
> performance and readability.  If you are interested in looking at it,
> it can be found here:

Yes it is :-P That's ok though, still is better than anything I can
write. I do lose patience with it after about seven minutes though :-(
What version of Lisp did you design it in sbcl?

-- 
May the Source be with you.
neo88 (Philip Haddad)
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87y8k4qta0.fsf@david-steuber.com>
······@truevine.net (neo88) writes:

> > My code is also currently dog slow.  It needs cleaning up for both
> > performance and readability.  If you are interested in looking at it,
> > it can be found here:
> 
> Yes it is :-P That's ok though, still is better than anything I can
> write. I do lose patience with it after about seven minutes though :-(
> What version of Lisp did you design it in sbcl?

I'm developing it in OpenMCL as the backend for Emacs + SLIME.  I have
also tested it under SBCL-darwin and SBCL-x86 Linux.  SBCL runs it a
shade faster.  OpenMCL is slowest when running inside SLIME.  It gets
faster if I fire up OpenMCL on the tty and do a (load (compile-file
"fractal.lisp")) from there.  I don't know why.  Maybe it can organize
the code a bit better that way.

I also wouldn't normally have so many global variables around, but I
have plans for calculating sequences of frames and I don't want to be
passing so much data around in function calls.

I've put in a few type declerations that I think I can get away with.
I haven't used optimize yet.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Paolo Amoroso
Subject: Re: Lisp readability
Date: 
Message-ID: <87k6vqaulb.fsf@plato.moon.paoloamoroso.it>
David Steuber <·····@david-steuber.com> writes:

> My version of the Mandelbrot program is a hack in progress.  It
[...]
> My code is also currently dog slow.  It needs cleaning up for both

This morning I happened to read the list of programs included in a
collection of TI Explorer software by JWZ.  Among them is a Mandelbrot
set program written in Common Lisp.  According to the notes I have
read, it should be easy to port.  I haven't checked the code, but I
assume the computation engine and the UI code are separate.

The notes describe this program as very fast.  You might be interested
in having a look at it.  I don't have an URL handy, but it's easy to
locate.  The distribution archive is named jwz.tgz and is available at
the CMU Common Lisp repository, in the system-specific folder for the
Explorer.


Paolo
-- 
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (Google for info on each):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: Bill Clementson
Subject: Re: Lisp readability
Date: 
Message-ID: <1b3ac8a3.0408241245.56aff827@posting.google.com>
David Steuber <·····@david-steuber.com> writes:

> Paolo Amoroso <·······@mclink.it> writes:
> > This morning I happened to read the list of programs included in a
> > collection of TI Explorer software by JWZ.  Among them is a Mandelbrot
> > set program written in Common Lisp.  According to the notes I have
[snip]
> I Googled about a bit, but couldn't find it. 

Paolo was probably referring to this link:
http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/impdep/explorer/jwz.tgz

--
Bill Clementson
From: Paolo Amoroso
Subject: Re: Lisp readability
Date: 
Message-ID: <87oekze5cd.fsf@plato.moon.paoloamoroso.it>
···············@yahoo.com (Bill Clementson) writes:

> Paolo was probably referring to this link:
> http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/impdep/explorer/jwz.tgz

That's it, thanks.


Paolo
-- 
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (Google for info on each):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87llg2l98s.fsf@david-steuber.com>
···············@yahoo.com (Bill Clementson) writes:

> Paolo was probably referring to this link:
> http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/impdep/explorer/jwz.tgz

Ok, thanks.

I wonder why googling for jwz.tgz didn't find it.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Pascal Bourguignon
Subject: Re: Lisp readability
Date: 
Message-ID: <87pt5ev17t.fsf@thalassa.informatimago.com>
David Steuber <·····@david-steuber.com> writes:

> ···············@yahoo.com (Bill Clementson) writes:
> 
> > Paolo was probably referring to this link:
> > http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/lisp/code/impdep/explorer/jwz.tgz
> 
> Ok, thanks.
> 
> I wonder why googling for jwz.tgz didn't find it.

I get it.  But either you have to bookmark the real search page:
    http://www.google.com/advanced_search
and paste jwz.tgz in the "with the EXACT PHRASE" field, or use double-quotes
an search for "jwz.tgz".

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we.
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87n00kqobg.fsf@david-steuber.com>
Paolo Amoroso <·······@mclink.it> writes:

> David Steuber <·····@david-steuber.com> writes:
> 
> > My version of the Mandelbrot program is a hack in progress.  It
> [...]
> > My code is also currently dog slow.  It needs cleaning up for both
> 
> This morning I happened to read the list of programs included in a
> collection of TI Explorer software by JWZ.  Among them is a Mandelbrot
> set program written in Common Lisp.  According to the notes I have
> read, it should be easy to port.  I haven't checked the code, but I
> assume the computation engine and the UI code are separate.
> 
> The notes describe this program as very fast.  You might be interested
> in having a look at it.  I don't have an URL handy, but it's easy to
> locate.  The distribution archive is named jwz.tgz and is available at
> the CMU Common Lisp repository, in the system-specific folder for the
> Explorer.

I Googled about a bit, but couldn't find it.  I did find this though:

http://synergy.as.cmu.edu/~geek/humor/academic_20programmers

This was with:

common lisp mandelbrot set site:cmu.edu

In the advanced search box.

The old fractint prgram was also very fast.  At least it was if you
just wanted to see a low magnification of the MSET.  If you wanted to
zoom into 50,000x normal size, it didn't seem to go fast anymore.
-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Frank Buss
Subject: Re: Lisp readability
Date: 
Message-ID: <cggdhj$22i$1@newsreader2.netcologne.de>
David Steuber <·····@david-steuber.com> wrote:

> My code is also currently dog slow.  It needs cleaning up for both
> performance and readability.  If you are interested in looking at it,
> it can be found here:
> 
>   http://www.david-steuber.com/~david/Lisp/fractal.lisp.txt

I've changed it to TGA output, which is a much more easier format and
works fine with CLISP. And I've stripped your fixed-point calculations,
which resulted in a faster program (test-point with 64x48: 10.2s old
program, 8.8s new program). I think there are better ways to improve
the precision with LONG-FLOAT or if you are using CLISP you can
specify the number of bits for the mantissa:

http://clisp.cons.org/impnotes/num-concepts.html#lfd

Your self-made floating point number made it really hard for the
compiler to optimize your program :-) 

But there is still something to optimize. Rendering 640x480 takes
24 minutes, but with a 6 year old assembler tuned program a fullscreen
mandelbrot calculation is finished in a second: 

ftp://ftp.heise.de/pub/ct/ctsi/3dnow.zip

And you have too much global variables, which makes the program
difficult to read. The new version: 

;;;; fractal.lisp -- an exploration of the Mandelbrot Set using
;;;; arbitrary sized integer math.
;;;;
;;;; By David Steuber with feedback from comp.lang.lisp and #lisp
;;;;
;;;; This software is put in the public domain by David Steuber

(defvar *escape-value* 2 
  "Numbers larger than this have escaped and are not part of the Mandelbrot Set")

;;; global variables to hold m-set related data
(defvar *aspect* 1
  "Aspect ratio of map")
(defvar *real-array* nil
  "C values along the real axis of the map")
(defvar *imag-array* nil
  "C values along the imaginary axis of the map")
(defvar *data-array* nil
  "itteration values for the map at each point")
(defvar *bitmap-width* 100
  "width of map in pixels")
(defvar *bitmap-height* 100
  "height of map in pixels")
(defvar *max-iterations* 1000
  "number of times to loop before deciding we are in the set")
(defvar *zoom* 1
  "the zoom factor")
(defvar *x* 0
  "x coordinate")
(defvar *y* 0
  "y coordinate")

(proclaim '(type fixnum *bitmap-width* *bitmap-height* *max-iterations*))

(defun mandelbrot-escape-fn (c-real c-imag)
  (let ((c (complex c-real c-imag)))
    (do ((z c (+ (* z z) c))
         (iteration 0 (1+ iteration)))
        ((or (>= iteration *max-iterations*)
             (> (abs z) 2))
         (return iteration)))))

(defun make-axis-array (len coord zoom &key (aspect 1) (reverse nil))
  (let ((my-array (make-array len)))
    (loop for i below len
          with size = (/ (* 4 aspect) zoom)
          with pixelsize = (/ size len)
          with start = (- coord (* (/ len 2) pixelsize))
          do (setf (aref my-array i) (float (+ start (* i pixelsize))))
          finally (if reverse (nreverse my-array)))
    my-array))

(defun best-iterations ()
  "Calculate the best max-iterations to use for zoom and bitmap width"
  (let ((rez (/ 1 (/ (* 4 *aspect*) *zoom* *bitmap-width*))))
    (the fixnum 
      (min most-positive-fixnum
           (max 256
                (round rez (log rez (* 2 pi))))))))
  
(defun set-mset-vars (&key (x *x*) (y *y*) (zoom *zoom*) (aspect *aspect*) 
                           (bitmap-width *bitmap-width*) (bitmap-height *bitmap-height*))
  (setf *real-array* (make-axis-array bitmap-width  x zoom :aspect aspect)
        *imag-array* (make-axis-array bitmap-height y zoom :reverse t)
        *data-array* (make-array (* bitmap-width bitmap-height) :element-type 'fixnum :initial-element 0)
        *bitmap-width* bitmap-width
        *bitmap-height* bitmap-height
        *aspect* aspect
        *x* x *y* y *zoom* zoom
        *max-iterations* (best-iterations)))

(defun compute-row (y x1 x2)
  (let* ((p1 (+ (* *bitmap-width* y) x1))
         (p2 (+ p1 x2))
         (escape-fn #'mandelbrot-escape-fn))
    (loop for i from x1 to x2
          for j from p1 to p2
          when (zerop (aref *data-array* j)) do
          (let ((iterations (funcall escape-fn (aref *real-array* i) (aref *imag-array* y))))
            (setf (aref *data-array* j) iterations)))))

(defun compute-column (x y1 y2)
  (let ((escape-fn #'mandelbrot-escape-fn))
    (loop for i from y1 to y2
          for j = (+ (* *bitmap-width* y1) x) then (+ j *bitmap-width*)
          when (zerop (aref *data-array* j)) do
          (let ((iterations (funcall escape-fn (aref *real-array* x) (aref *imag-array* i))))
            (setf (aref *data-array* j) iterations)))))

(defun check-edges (left top right bottom)
  "If all the values are the same, fill the region and return t"
  (declare (type fixnum left top right bottom))
  (let ((v (aref *data-array* (+ (* top *bitmap-width*) left)))
        (r t))
    (loop for i from (+ (* top *bitmap-width*) left) to (+ (* top *bitmap-width*) right)
          for j from (+ (* bottom *bitmap-width*) left) to (+ (* bottom *bitmap-width*) right)
          unless (= v (aref *data-array* i) (aref *data-array* j)) return (setf r nil))
    (loop for c from top to bottom
          for i = (+ (* top *bitmap-width*) left) then (+ i *bitmap-width*)
          for j = (+ (* top *bitmap-width*) right) then (+ j *bitmap-width*)
          unless (= v (aref *data-array* i) (aref *data-array* j)) return (setf r nil))
    (when r
      (loop for j from (1+ top) to (1- bottom)
            do (loop for i from (+ (* j *bitmap-width*) (1+ left)) to (+ (* j *bitmap-width*) (1- right))
                     do (setf (aref *data-array* i) v))))
    r))

(defun quarter-the-map (left top right bottom)
  "Divide the map into four quarters"
  (declare (type fixnum left top right bottom))
  (cond ((< (- right left) 2) nil)      ; done
        ((< (- bottom top) 2) nil)      ; also done
        ((check-edges left top right bottom) nil) ; done here also
        (t (let ((vmid (+ top (round (- bottom top) 2)))
                 (hmid (+ left (round (- right left) 2))))
             (declare (type fixnum vmid hmid))
             (compute-row vmid (1+ left) (1- right))
             (compute-column hmid (1+ top) (1- bottom))
             (quarter-the-map left top hmid vmid)
             (quarter-the-map hmid top right vmid)
             (quarter-the-map hmid vmid right bottom)
             (quarter-the-map left vmid hmid bottom)))))

(defun mandelbrot-set ()
  "Calculate bitmap data for the Mandelbrot Set"
  (compute-row 0 0 (1- *bitmap-width*))
  (compute-row (1- *bitmap-height*) 0 (1- *bitmap-width*))
  (compute-column 0 1 (- *bitmap-height* 2))
  (compute-column (1- *bitmap-width*) 1 (- *bitmap-height* 2))
  (quarter-the-map 0 0 (1- *bitmap-width*) (1- *bitmap-height*)))

;;; Color pallet logic.  Making a pallet and mapping pallet colors to iterations.

(defvar *color-pallet* #((255 255 255)))
(defvar *mset-color* (list 0 0 0))

(defun interval (lower upper n)
  (let ((increment (/ (- upper lower) (+ n 1))))
    (loop for i = (+ lower increment) then (+ i increment)
          repeat n 
          collect (round i))))

(defun mapci (fn cl il)
  (if (cadr cl)
      (let ((r1 (car cl))
            (r2 (cadr cl))
            (i (car il)))
        (cons r1 
              (cons (funcall fn r1 r2 i)
                    (mapci fn (cdr cl) (cdr il)))))
      (cons (car cl) nil)))

(defun flatten-tree (lst)
  (when lst
    (let ((e (car lst)))
      (if (atom e)
          (cons e (flatten-tree (cdr lst)))
          (nconc (flatten-tree e) (flatten-tree (cdr lst)))))))

(defun make-color-pallet (colors)
  "'((r g b) interval (r g b) interval (r g b) ...) where interval is number of colors to tween"
  (let (clst ilst) 
    (mapcar (lambda (e) (when (listp e) (push e clst))) colors)
    (mapcar (lambda (e) (when (atom e) (push e ilst))) colors)
    (let ((rlst (mapcar #'car clst))
          (glst (mapcar #'cadr clst))
          (blst (mapcar #'caddr clst)))
      (setf clst nil)
      (mapcar (lambda (r g b) (push (list r g b) clst))
              (flatten-tree (mapci #'interval rlst ilst))
              (flatten-tree (mapci #'interval glst ilst))
              (flatten-tree (mapci #'interval blst ilst)))
      (setf *color-pallet* (make-array (length clst)))
      (let ((i 0))
        (dolist (c clst i)
          (setf (aref *color-pallet* i) c)
          (incf i))))))

(make-color-pallet '((255 0 0) 32 (255 255 0) 32 (0 255 0) 32 (0 255 255) 32 (0 0 255) 32 (255 0 255) 31 (255 0 8)))

;;; TGA stuff

(defun write-tga (image filename)
  (let* ((dimension (array-dimensions image))
         (width (nth 0 dimension))
         (height (nth 1 dimension)))
    (with-open-file
        (tga filename
             :direction :output
             :if-exists :supersede
             :element-type 'unsigned-byte)
      (dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
                          (mod width 256) (floor width 256)
                          (mod height 256) (floor height 256) 24 0))
        (write-byte byte tga))
      (loop for y from 0 to (1- height) do
            (loop for x from 0 to (1- width) do
                  (write-byte (aref image x y 0) tga)
                  (write-byte (aref image x y 1) tga)
                  (write-byte (aref image x y 2) tga))))))

(defun write-fractal-image-tga-file (filespec)
  "Creates a TGA file using MM byte order from the fractal data"
  (with-open-file
      (tga filespec
           :direction :output
           :if-exists :supersede
           :element-type 'unsigned-byte)
    (dolist (byte (list 0 0 2 0 0 0 0 0 0 0 0 0
                        (mod *bitmap-width* 256) (floor *bitmap-width* 256)
                        (mod *bitmap-height* 256) (floor *bitmap-height* 256) 24 0))
      (write-byte byte tga))
    (loop for i below (length *data-array*)
          for j = 0 then (+ j 3)
          with b = 0
          do (progn
               (if (= *max-iterations* (aref *data-array* i))
                   (setf b *mset-color*)
                   (setf b (aref *color-pallet* (mod (round (log (aref *data-array* i) (sqrt 2))) (length *color-pallet*)))))
               (write-byte (car b) tga)
               (write-byte (cadr b) tga)
               (write-byte (caddr b) tga)))))

;;; End of TGA stuff.  Time to explore.

(defun test-point ()
  "Nice spot in the image to test stuff with."
  (set-mset-vars :x -12001/16384 :y 1249/8192 :zoom 1024 :bitmap-width 640 :bitmap-height 480
                 :aspect 640/480)
  (mandelbrot-set)
  (write-fractal-image-tga-file "/tmp/test-fractal.tga"))

(defun quick-test-point ()
  "Nice spot in the image to test stuff with."
  (set-mset-vars :x -12001/16384 :y 1249/8192 :zoom 1024 :bitmap-width 200 :bitmap-height 200
                 :aspect 1)
  (mandelbrot-set)
  (write-fractal-image-tga-file "/tmp/quick-test-fractal.tga"))

(defun zoom (&key x y z)
  "Zoom on x y (as pixel coordinates) by factor z.  Previous map
must already have been calculated."
  (let (nx ny nz)
    (if x
        (setf nx (aref *real-array* x))
        (setf nx *x*))
    (if y
        (setf ny (aref *imag-array* y))
        (setf ny *y*))
    (if z
        (setf nz (* *zoom* z))
        (setf nz *zoom*))
    (format t "~S~%" (set-mset-vars :x nx :y ny :zoom nz))
    (mandelbrot-set)
    (write-fractal-image-tga-file "/tmp/foo.tga")
    (list *x* *y* *zoom*)))

;(-768047/1048576 318601/2097152 4096)
;(-24577759/33554432 2547397/16777216 262144)


-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87fz6al6qc.fsf@david-steuber.com>
Frank Buss <··@frank-buss.de> writes:

> David Steuber <·····@david-steuber.com> wrote:
> 
> > My code is also currently dog slow.  It needs cleaning up for both
> > performance and readability.  If you are interested in looking at it,
> > it can be found here:
> > 
> >   http://www.david-steuber.com/~david/Lisp/fractal.lisp.txt
> 
> I've changed it to TGA output, which is a much more easier format and
> works fine with CLISP. And I've stripped your fixed-point calculations,

I'll certainly take the TGA code.  I was going with TIFF because I
thought that would be convinient.  I have other software for file
format conversions though.

> which resulted in a faster program (test-point with 64x48: 10.2s old
> program, 8.8s new program). I think there are better ways to improve
> the precision with LONG-FLOAT or if you are using CLISP you can
> specify the number of bits for the mantissa:
> 
> http://clisp.cons.org/impnotes/num-concepts.html#lfd

I don't really want to lock into Clisp (unless that will run the
fastest).  My Perl/C version used IEEE-754 doubles and was a lot
faster.  The problem is, I used up all 53 bits of mantissa.

> Your self-made floating point number made it really hard for the
> compiler to optimize your program :-) 

Do you think there is another way (besides what you just mentioned
above) to deal with the high precision required for really deep zooms?
The current state of my code will allow zooming in as far as memory
allows (although I have restricted the max-iterations to a fixnum).
The problem is, I can make it take over seven minutes to calculate a
single pixel.

I've only just started to play with compiler optimizations.  SBCL puts
out a note for everything it can't optimize when (declare (optimize
speed)) is used.  I haven't yet figured out how to tell the compiler
that an array I access with aref contains fixnums.  SVREF apparantly
only works on simple vectors which don't seem to include arrays that
have had their element-type set to something other than t.  I think
the CLHS said something about that.

> But there is still something to optimize. Rendering 640x480 takes
> 24 minutes, but with a 6 year old assembler tuned program a fullscreen
> mandelbrot calculation is finished in a second: 
> 
> ftp://ftp.heise.de/pub/ct/ctsi/3dnow.zip

Just imagine how slow I could make the program in Python or Perl!

I don't think assembler will help me.  I'm hacking this up on a Mac
although I have done some testing on Linux x86.

A long time ago, I had a fixed int algorithm in 80386 assembler which
did the computations in registers.  I was simply relying on the fact
that when you MUL to 32 bit ints, you get a 64 bit result.  I just
took the highword.  I never generalized that to multiple words.

> And you have too much global variables, which makes the program
> difficult to read.

Yes, that I know.  I need to modularize my code a bunch and get rid of
those globals.  I might do it with CLOS or perhaps some closures.

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Doug Philips
Subject: Re: Lisp readability
Date: 
Message-ID: <0001HW.BD4F80440033B2FEF04075B0@news.nauticom.net>
On Sun, 22 Aug 2004 15:09:56 -0400, Frank Buss wrote
(in article <············@newsreader2.netcologne.de>):
> Doug Philips <····@mac.com> wrote:
>> Although, what ultimately makes that code unreadable is not the
>> style of indentation or the placement of spaces, but that there is just
>> too much going on "in one place" in the first place.
> 
> Yes, you are right. Currently I'm reading "On Lisp" and I start to 
> understand the bottom-up concept. You build your own language with low-
> level functions and macros, and use this in higher-level functions until 
> you have your program. Of course, somtimes you have to go down again, 
> doing some refactoring, but this is easy with the interactive Lisp 
> environment.

Top down or bottom up, I get uncomfortable when I see a function with
more than about 4-5 lines of nicely formatted code. Macros I'm willing to let
get a bit longer, with-gensyms is something that chews up a whole line itself
sometimes, etc.

Actually this fondness for brevity was something that I really appreciated
about On Lisp. Its also something espoused by Forth. Its very hard to do in
C, though C++ is a bit less noisy. I've "shed a tear" and moved on
(Kent Beck, Test Driven Design) with half-page functions too. But always with
the feeling that I've missed something important.


> If you design carefully the building blocks, you can reuse it for 
> different tasks. Indention is not so important for readability, as long 
> as the functions are short and doing only one thing, if possible without 
> side-effects. Another version of the mandelbrot program:

That's definitely better, but having the escape defun save the square root call
(implicit in multiplying complex numbers, right?) when its going to happen
in the calculation (do) for the next Z value anyways...
Also the cute ascii-ization is too obscure, but at least not because its too
many lines of code. ;-)

<D\'gou
From: Frank Buss
Subject: Re: Lisp readability
Date: 
Message-ID: <cgdjor$75c$1@newsreader2.netcologne.de>
Doug Philips <····@mac.com> wrote:

> That's definitely better, but having the escape defun save the square
> root call (implicit in multiplying complex numbers, right?) when its
> going to happen in the calculation (do) for the next Z value
> anyways...

I don't understand exactly what you mean. My first version used abs(z)<2. 
Then I used the square function from someone in the original thread, 
because abs(z) means sqr(z_img*z_img+z_rel*z_rel), so it can be 
simplified by z_img*z_img+z_rel*z_rel<2*2. But you are right, there are 
at least 2 multiplications and one addition too much for every loop 
iteration, because the z*z iteration can use some of the calculations for 
the escape test.

> Also the cute ascii-ization is too obscure, but at least
> not because its too many lines of code. ;-)

Yes, perhaps this is only something for geeks like me :-)
I've done similiar things decades ago in BASIC on a C64 and with a MPS801 
matrix printer (because the resolution of 40 chars a line was not enough 
for displaying it on screen), printing an image by matching the best 
characters, like this one, but not so good (would be a nice project for 
Lisp, and not too difficult with my char-table at
http://www.frank-buss.de/tmp/mandelbrot.lisp.txt )

http://nico.f-451.net/img/jpg2asc.html (view it from > 4 meters distance 
to the display)

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Doug Philips
Subject: Re: Lisp readability
Date: 
Message-ID: <0001HW.BD4FD32F00472229F04075B0@news.nauticom.net>
On Mon, 23 Aug 2004 16:23:55 -0400, Frank Buss wrote
(in article <············@newsreader2.netcologne.de>):
> Doug Philips <····@mac.com> wrote:
>>> That's definitely better, but having the escape defun save the square
>> root call (implicit in multiplying complex numbers, right?) when its
>> going to happen in the calculation (do) for the next Z value
>> anyways...
> 
> I don't understand exactly what you mean. My first version used abs(z)<2. 
> Then I used the square function from someone in the original thread, 
> because abs(z) means sqr(z_img*z_img+z_rel*z_rel), so it can be 
> simplified by z_img*z_img+z_rel*z_rel<2*2. But you are right, there are 
> at least 2 multiplications and one addition too much for every loop 
> iteration, because the z*z iteration can use some of the calculations for 
> the escape test.

Ah, now this is getting more interesting. Yes, you are getting at (or towards)
what I had said, though perhaps I said it too tersely. Why not just use:
(< (abs z) 2)? For whom has it been simplified to the longer/noisier < + * * obscure-constant
form? That would make sense if it lead to further refactorings which could be used
to exploit the z*z iteration, as you picked up on. But again, only if it made the code
clearer to understand (compiler macros transform it to something that runs faster if
profiling shows that to be a bottle neck). In the form you posted, it is less clear
than if you'd used abs directly, and it is not that much more efficient because its not
leveraged with the calcs in the loop calling the escape function (i.e. a worser of both
worlds). But the clarity is only partly the number of symbols in 'escape' and mostly the
confusion of "why" (rather than what).

 
> http://nico.f-451.net/img/jpg2asc.html (view it from > 4 meters distance 
> to the display)

Cute.

<D\'gou
From: Frank Buss
Subject: Re: Lisp readability
Date: 
Message-ID: <cgdo9b$e5i$1@newsreader2.netcologne.de>
Doug Philips <····@mac.com> wrote:

> Why not just use: (< (abs z) 2)? For whom has it been simplified to the
> longer/noisier < + * * obscure-constant form? 

yes, this was premature optimization. I've timed it and the whole loop was 
not slower with ABS than with the < + * *-form.

-- 
Frank Bu�, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Edi Weitz
Subject: Re: Lisp readability
Date: 
Message-ID: <87u0uvfljf.fsf@bird.agharta.de>
On 22 Aug 2004 10:43:20 GMT, ···@zedat.fu-berlin.de (Stefan Ram) wrote:

>   When I want to read this, the first thing I do, is to reformat
>   it, so that /every level/ of nesting indents by /the same
>   number/ of two positions:
>
> ( loop for y from -1 to 1.1 by 0.1 do
>   ( loop for x from -2 to 1 by 0.04 do
>     ( let* 
>       ( ( c 126)
>         ( z ( complex x y ))
>         ( a z ))
>       ( loop 
>         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
>         while ( > ( decf c ) 32 )) 
>       ( princ ( code-char c ))))
>   ( format t "~%" ))

That's just plain ugly. Yuck!

-- 

"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Thomas Schilling
Subject: Re: Lisp readability
Date: 
Message-ID: <opsc4zi8xstrs3c0@news.CIS.DFN.DE>
Edi Weitz <········@agharta.de> wrote:

> On 22 Aug 2004 10:43:20 GMT, ···@zedat.fu-berlin.de (Stefan Ram) wrote:
>
>>   When I want to read this, the first thing I do, is to reformat
>>   it, so that /every level/ of nesting indents by /the same
>>   number/ of two positions:
>>
>> ( loop for y from -1 to 1.1 by 0.1 do
>>   ( loop for x from -2 to 1 by 0.04 do
>>     ( let*
>>       ( ( c 126)
>>         ( z ( complex x y ))
>>         ( a z ))
>>       ( loop
>>         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
>>         while ( > ( decf c ) 32 ))
>>       ( princ ( code-char c ))))
>>   ( format t "~%" ))
>
> That's just plain ugly. Yuck!

I second this--not because of your indentation but because of your `LISS' 
(Lot's of Insanely Stupid Spaces). That really obscures the program's 
structure. It, well, just scatters the code. Hence my (our) perceived 
ugliness.

I guess it also takes much longer to type.

Your indentation is ok, though it also slows down coding speed if your 
editor doesn't indent correctly the first time (i guess this would be the 
case with your first LOOPs). Splitting up more complex expressions into 
several lines may look ugly at first, but if it helps associating the 
function arguments it's ok IMHO. E.g.

  (foo (bar (+ (* 3 4) x) 4)
       (boing dong (deng ding) dodo)
       duff)

as opposed to

  (foo (bar (+ (* 3 4) x) 4) (boing dong (deng ding) dodo) duff)

-- 
      ,,
     \../   /  <<< The LISP Effect
    |_\\ _==__
__ | |bb|   | _________________________________________________
From: David Steuber
Subject: Re: Lisp readability
Date: 
Message-ID: <87r7py66f1.fsf@david-steuber.com>
Edi Weitz <········@agharta.de> writes:

> That's just plain ugly. Yuck!

I think the word you were looking for was irregular ;-)

-- 
An ideal world is left as an excercise to the reader.
   --- Paul Graham, On Lisp 8.1
From: Paolo Amoroso
Subject: Re: Lisp readability
Date: 
Message-ID: <877jrr8gqn.fsf@plato.moon.paoloamoroso.it>
···@zedat.fu-berlin.de (Stefan Ram) writes:

>   When I want to read this, the first thing I do, is to reformat
>   it, so that /every level/ of nesting indents by /the same
>   number/ of two positions:
>
> ( loop for y from -1 to 1.1 by 0.1 do
>   ( loop for x from -2 to 1 by 0.04 do
>     ( let* 
>       ( ( c 126)
>         ( z ( complex x y ))
>         ( a z ))
>       ( loop 
>         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
>         while ( > ( decf c ) 32 )) 
>       ( princ ( code-char c ))))
>   ( format t "~%" ))

My eyes hurt, I need collyrium.


Paolo
-- 
Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (Google for info on each):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
From: Espen Vestre
Subject: Re: Lisp readability
Date: 
Message-ID: <kw7jrqcn17.fsf@merced.netfonds.no>
···@zedat.fu-berlin.de (Stefan Ram) writes:

> ( loop for y from -1 to 1.1 by 0.1 do
>   ( loop for x from -2 to 1 by 0.04 do
>     ( let* 
>       ( ( c 126)
>         ( z ( complex x y ))
>         ( a z ))
>       ( loop 
>         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
>         while ( > ( decf c ) 32 )) 
>       ( princ ( code-char c ))))
>   ( format t "~%" ))

Ouch. How can anyone _parse_ something like that? My eyes hurt!
-- 
  (espen)
From: Coby Beck
Subject: Re: Lisp readability
Date: 
Message-ID: <B3rWc.103$A8.98@edtnps89>
"Espen Vestre" <·····@*do-not-spam-me*.vestre.net> wrote in message
···················@merced.netfonds.no...
> ···@zedat.fu-berlin.de (Stefan Ram) writes:
>
> > ( loop for y from -1 to 1.1 by 0.1 do
> >   ( loop for x from -2 to 1 by 0.04 do
> >     ( let*
> >       ( ( c 126)
> >         ( z ( complex x y ))
> >         ( a z ))
> >       ( loop
> >         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
> >         while ( > ( decf c ) 32 ))
> >       ( princ ( code-char c ))))
> >   ( format t "~%" ))
>
> Ouch. How can anyone _parse_ something like that? My eyes hurt!
> -- 
>   (espen)

I had to do it:
(loop for y from -1 to 1.1 by 0.1 do
      (loop for x from -2 to 1 by 0.04 do
            (let* ((c 126)
                   (z (complex x y))
                   (a z))
              (loop while (< (abs (setq z (+ (* z z) a))) 2)
                    while (> (decf c) 32))
              (princ (code-char c))))
      (format t "~%"))

to Stefan Ram:  consider if the difference between these two is sufficiently
compelling to warrant such a break with the near universally excepted styles
you have issue with or if you can just get used to the second format.
Unless you will write all your code forever just for yourself, it is not a
zero-cost change to your preferred style!

-- 
Coby Beck
(remove #\Space "coby 101 @ big pond . com")
From: Thomas A. Russ
Subject: Re: Lisp readability
Date: 
Message-ID: <ymismabccf2.fsf@sevak.isi.edu>
"Coby Beck" <·····@mercury.bc.ca> writes:

> 
> 
> > ···@zedat.fu-berlin.de (Stefan Ram) writes:
> >
> > > ( loop for y from -1 to 1.1 by 0.1 do
> > >   ( loop for x from -2 to 1 by 0.04 do
> > >     ( let*
> > >       ( ( c 126)
> > >         ( z ( complex x y ))
> > >         ( a z ))
> > >       ( loop
> > >         while ( < ( abs ( setq z ( + ( * z z ) a ))) 2 )
> > >         while ( > ( decf c ) 32 ))
> > >       ( princ ( code-char c ))))
> > >   ( format t "~%" ))
> 
> I had to do it:
> (loop for y from -1 to 1.1 by 0.1 do
>       (loop for x from -2 to 1 by 0.04 do
>             (let* ((c 126)
>                    (z (complex x y))
>                    (a z))
>               (loop while (< (abs (setq z (+ (* z z) a))) 2)
>                     while (> (decf c) 32))
>               (princ (code-char c))))
>       (format t "~%"))
> 
> to Stefan Ram:  consider if the difference between these two is sufficiently
> compelling to warrant such a break with the near universally excepted styles
> you have issue with or if you can just get used to the second format.
> Unless you will write all your code forever just for yourself, it is not a
> zero-cost change to your preferred style!

Yes, I will have to agree with this comment.

The initial example, where the parens are set off by whitespace just
serves (at least to me) to highlight the parentheses, instead of letting
them more or less fade into the background in the second version.
Of course, since I've been reading Lisp code for 25+ years, it may just
be something I've gotten used to seeing.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Tayssir John Gabbour
Subject: Re: Lisp readability
Date: 
Message-ID: <866764be.0408230225.3c0e9d2f@posting.google.com>
Chris Capel wrote:
> Lisp is really readable.

Yes. A goal of lisp seems to be about the simplicity of coding the
first ideas which come to mind. Such ideas are often the most natural.
Now, it might turn out that you didn't foresee the bad consequences of
that first idea; but lisp is also a mutable substance, so one can
"refactor" things relatively well too.

Of course, that is an eternal goal, but most languages wish one to
jump through "necessary" hoops.

An example came from my Python work, where we accepted outside data,
which users might want to extract useful data from even if corrupted.
My first instinct was to simply signal a warning, which the function's
caller may take seriously if it wishes. Or ignore it otherwise.
However, Python does not support that possiblity, so I left it alone,
and someone else coded formal Error Objects. It's beginning to look
like one of those big budget Hollywood movies where the plot goes
absolutely nowhere.


I watched these videos:
http://ll2.ai.mit.edu/

And it demonstrates a simple algorithm: find out what lisp has that
other languages don't, and consider that a scary thing.
(defun why-is-common-lisp-scary (lisp-features other-langs-features)
  (set-difference lisp-features other-langs-features))

Maybe set-difference's test should be a random choice between
#'eq..#'equalp. After all, the Ruby guy pointed out that ()s are
scary... but he didn't notice how <> + marketing has taken the world
by storm. So that excuse has gone the way of dinosaur boogiemen like
GC.

The Microsoft guy compared macros to the evil of gotos. Well, the
author of Goto Considered Harmful complained how people only cited the
title without reading the paper -- which was titled "A case against
the goto statement" before someone else changed it. An important part
of computing which was scapegoated for the sins of software
engineering. If you have an early language like Fortran where might
have been no way out of using goto, then there would have been an
overuse. Lisp has goto, and the only times you really see it is inside
macroexpansions: power keeping power in check.

But there's no doubt a boost that lispers are self-selected, which is
how the world should work. The Microsoftie has a point; not
necessarily to the extreme that he intended, but that slow organic
growth is better overall than forcing people to use a language they
don't understand.


> So I'm wondering.  Why isn't this touted more as an advantage of Lisp?

I guess it's hard to communicate with people trained to desire
"benevolent dictators" and "trusted lieutenants." If they wished hard
enough, they can believe a dictator knows what's right for everyone's
domain.


MfG,
Tayssir