From: K. Ari Krupnikov
Subject: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <86fz3r47g0.fsf@deb.lib.aero>
In my attempts to transition to Lisp, I'm having a hard time
organizing my data in hierarchical structures. In every language I've
used so far, hierarchical data structures are useful abstractions for
dealing with complexity. Different languages have different ways of
defining these structures (structures in C, classes in Java, elements
in XML), but the way one navigates to a datum is essentially similar:

C:     anAirport.runways[0].highEnd.location.latitude

Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()

XPath: $anAirport/runway[1]··················@latitude

This is a simplification of an actual application I'm working
with. The examples imply straightforward structures in their
respective languages. What should be the Lisp equivalent?

My first attempt was to define a bunch of structures:

(location-latitude
  (rwy-end-location
    (runway-high-end
      (nth 0
        (airport-runways
          (an-airport))))))

I found this difficult to read, for two reasons. Both of them seem to
stem from the fact that Lisp uses functions to access structure slots,
as opposed to some dedicated mechanism. First, the order is reversed:
I tend to think of trees (including nested lists in Lisp) as
originating at top left corner of my screen and growing right and
down; my Lisp expression above goes in the opposite direction -- the
root, "an-airport" is at the right bottom of my expression. Second,
the long function names that include type names make expressions much
longer and less readable. I could solve the second problem by using
:conc-name nil or, I imagine, by defining accessors as CLOS
methods[1]. In this case, the expression would become

(latitude (location (high-end (nth 0 (runways (an-airport))))))

which still reads in the wrong direction.

Is this just a temporary difficulty adjusting to Lisp, and being able
to reverse accessor lists is simply a skill that comes with
experience, or am I missing a better Lisp way to organize hierarchical
data?

Ari.

[1] I decided to first learn "straight" CL without CLOS -- is that a
reasonable approach?

-- 
Elections only count as free and trials as fair if you can lose money
betting on the outcome.

From: Barry Margolin
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <barmar-531AE9.08152203112004@comcast.dca.giganews.com>
In article <··············@deb.lib.aero>,
 ···@lib.aero (K. Ari Krupnikov) wrote:

> I found this difficult to read, for two reasons. Both of them seem to
> stem from the fact that Lisp uses functions to access structure slots,
> as opposed to some dedicated mechanism. First, the order is reversed:
> I tend to think of trees (including nested lists in Lisp) as
> originating at top left corner of my screen and growing right and
> down; my Lisp expression above goes in the opposite direction -- the
> root, "an-airport" is at the right bottom of my expression. Second,
> the long function names that include type names make expressions much
> longer and less readable.

This is curious, because the Lisp way is similar to the way we refer to 
things in natural language.  Wouldn't you say "latitude of the high end 
of the first runway of the airport", rather than "airport's first 
runway's high end's latitude"?  We use the latter syntax for short 
phrases (e.g. "airport's lattitude"), but as the phrase gets longer I 
think most people are likely to switch to the first syntax.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <87bref3pol.fsf@qrnik.zagroda>
Barry Margolin <······@alum.mit.edu> writes:

> This is curious, because the Lisp way is similar to the way we refer to 
> things in natural language.  Wouldn't you say "latitude of the high end 
> of the first runway of the airport", rather than "airport's first 
> runway's high end's latitude"?

Being consistent with the natural language order doesn't imply that
it's convenient.

When many functions are composed, I usually prefer to read and write
them in the order they are applied, and to avoid nesting parentheses
proportionally to the number of functions. While I generally dislike
the syntax of traditional OO languages, their advantage is that
composition of method applications has a convenient order and doesn't
require nesting of parentheses.

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/
From: K. Ari Krupnikov
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <861xfan13v.fsf@deb.lib.aero>
Marcin 'Qrczak' Kowalczyk <······@knm.org.pl> writes:

> Barry Margolin <······@alum.mit.edu> writes:
> 
> > This is curious, because the Lisp way is similar to the way we refer to 
> > things in natural language.  Wouldn't you say "latitude of the high end 
> > of the first runway of the airport", rather than "airport's first 
> > runway's high end's latitude"?
> 
> Being consistent with the natural language order doesn't imply that
> it's convenient.

That, and the fact that different natural languages have different
conventions for this. English happens to be my third language -- I
just use a good spell-checker.

Ari.

-- 
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
From: Barry Margolin
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <barmar-CB0F91.20364603112004@comcast.dca.giganews.com>
In article <··············@qrnik.zagroda>,
 Marcin 'Qrczak' Kowalczyk <······@knm.org.pl> wrote:

> Barry Margolin <······@alum.mit.edu> writes:
> 
> > This is curious, because the Lisp way is similar to the way we refer to 
> > things in natural language.  Wouldn't you say "latitude of the high end 
> > of the first runway of the airport", rather than "airport's first 
> > runway's high end's latitude"?
> 
> Being consistent with the natural language order doesn't imply that
> it's convenient.

In general, Lisp is more verbose than C.  Not just the basic syntax, but 
there's a tradition of using long, descriptive function names, which is 
codified in the default names of structure accessors.

So why would you expect this aspect to be as concise as C?

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: David Sletten
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <jd2id.59850$Kl3.17825@twister.socal.rr.com>
K. Ari Krupnikov wrote:

> In my attempts to transition to Lisp, I'm having a hard time
> organizing my data in hierarchical structures. In every language I've
> used so far, hierarchical data structures are useful abstractions for
> dealing with complexity. Different languages have different ways of
> defining these structures (structures in C, classes in Java, elements
> in XML), but the way one navigates to a datum is essentially similar:
> 
Your problem doesn't seem to be organizing data in a hierarchy--it seems 
to be a matter of syntax. CLOS allows you to do any OOP that Java can 
and more. You can use inheritance to model hierarchies or use 
composition to model your situation here: an airport 'has-a' runway(s).


> Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()

> 
> (location-latitude
>   (rwy-end-location
>     (runway-high-end
>       (nth 0
>         (airport-runways
>           (an-airport))))))
> 
Part of the problem here is that you didn't faithfully translate your 
Java. In particular, anAirport is not a method, while getRunway() takes 
an integer argument. With this in mind, and renaming some methods we get:
(get-latitude (get-location (get-high-end (get-runway an-airport 0))))

This isn't necessarily the best way to do it. This is probably better:
(let* ((this-runway (get-runway an-airport 0))
        (latitude (get-latitude (get-location (get-high-end 
this-runway))))) . . . )

Another point to consider is that your Java code hides the 
implementation of the container for the runways. Your Lisp code commits 
you to a list.


> I found this difficult to read, for two reasons. Both of them seem to
> stem from the fact that Lisp uses functions to access structure slots,
> as opposed to some dedicated mechanism. First, the order is reversed:
> I tend to think of trees (including nested lists in Lisp) as
> originating at top left corner of my screen and growing right and
> down; my Lisp expression above goes in the opposite direction -- the
> root, "an-airport" is at the right bottom of my expression. 

Personally, I don't find the Lisp hard to read. Maybe it just takes some 
time to get used to. You must also bear in mind, however, that Lisp uses 
a more general form of OO than Java. Java determines the method to call 
based on the instance on which is invoked. This is called the 
message-passing model--you send a message to an object to cause it to 
perform some action. Lisp uses the generic function model. If you 
consider a Java object as an implicit argument to its methods (i.e., 
this), you can see that Java only specializes on a single argument. CLOS 
allows specialization on any argument to a method. See Peter Seibel's 
drum/stick example in chapter 14 
(http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html).


> 
> [1] I decided to first learn "straight" CL without CLOS -- is that a
> reasonable approach?
> 
I think many Lisp gurus would advise you to learn CLOS and avoid 
DEFSTRUCT. See Peter's book, for example.

David Sletten
From: Luis Oliveira
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <7rsm52-sd3.ln1@netman.ath.cx>
David Sletten skribis:
> I think many Lisp gurus would advise you to learn CLOS and avoid 
> DEFSTRUCT. See Peter's book, for example.

Why so? Paul Graham does the exact opposite. What's wrong with
DEFSTRUCT?


-- 
Luís Oliveira                                         Lisp is the red pill.
Reply-To: luismbo (@) netcabo (.) pt         -- John Fraser, comp.lang.lisp
Equipa Portuguesa do Translation Project
http://www2.iro.umontreal.ca/~pinard/po/registry.cgi?team=pt
From: Frode Vatvedt Fjeld
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <2hbrefvyp5.fsf@vserver.cs.uit.no>
Luis Oliveira <·············@deadspam.com> writes:

> What's wrong with DEFSTRUCT?

It does not provide for dynamism. There's no proper protocol for what
happens when a defstruct declaration is changed. This is a serious
break with the dynamic paradigm that I find to be quite fundamental
to Common Lisp. Furthermore, defstruct provides really nothing of
substance over defclass--with the possible exception of slightly
better accessor performance in some implementations.

-- 
Frode Vatvedt Fjeld
From: K. Ari Krupnikov
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <86lldila37.fsf@deb.lib.aero>
David Sletten <·····@slytobias.com> writes:

> Part of the problem here is that you didn't faithfully translate your
> Java.

You will note that only one of my examples was Java. I tried to
present the most common, idiomatic constructs in three different
languages. Of the three, Java is the only one with functional
semantics for accessors.

> In particular, anAirport is not a method

It is a variable.

> while getRunway() takes an integer argument.

In Java. In C, it is an array subscript and in XPath it is a
predicate, a shorthand for [location()=1] (XPath uses 1-based
indexing).

> With this in mind, and renaming some methods we get: (get-latitude
> (get-location (get-high-end (get-runway an-airport 0))))
> 
> This isn't necessarily the best way to do it.

Of course. Forcing one language's conventions on another is seldom a
good idea. Conventions evolve pursuant to language features and
constraints. I'm here to learn /Lisp/ conventions, and through them,
features and constraints of the language.

Note also that your get-location, unless it is a method specialized on
runway-end, will break for other things that have locations --
airports have locations of their own, for instance.

> This is probably better: (let* ((this-runway (get-runway an-airport
> 0)) (latitude (get-latitude (get-location (get-high-end
> this-runway))))) . . . )
> 
> Another point to consider is that your Java code hides the
> implementation of the container for the runways. Your Lisp code
> commits you to a list.

As much as the C implementation commits me to an array or the XML
implementation, to a list of (runway+). It seemed to me that a list
was the most appropriate Lisp structure to use here. Let me know if
another mechanism would fit better.

> You must also bear in mind, however, that
> Lisp uses a more general form of OO than Java.

[message-passing-vs-specialization-on-arguments discussion snipped]

What's this fascination with bashing Java? There is a reason I'm
asking questions here and not in comp.lang.java. You needn't spend
effort explaining to me that Lisp has a more general model.

I gave three examples, only one of them was Java, and only one an OO
language. Neither C nor XPath are OO, but both navigate hierarchical
structures left-to-right. In Java, a convention evolved to use methods
for field access to protect these fields from unexpected
modification. This attaches unnecessary functional semantics to the
simple operation of dereferencing a variable. In particular, accessor
methods in Java may have side effects (bad form to be sure, but
possible). What bothered me about Lisp structures is that defstuct
attaches the same functional semantics to this operation.

> > [1] I decided to first learn "straight" CL without CLOS -- is that a
> > reasonable approach?
> >
> I think many Lisp gurus would advise you to learn CLOS and avoid
> DEFSTRUCT. See Peter's book, for example.

As Luis Oliveira mentioned, Paul Graham seemed to advocate that
approach in his /ANSI Common LISP/. That the book I've been working
from.

Ari.

-- 
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
From: David Sletten
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <YCfid.35283$jo2.23192@twister.socal.rr.com>
K. Ari Krupnikov wrote:


> 
> As much as the C implementation commits me to an array or the XML
> implementation, to a list of (runway+). It seemed to me that a list
> was the most appropriate Lisp structure to use here. Let me know if
> another mechanism would fit better.
> 
> 
Your Java example hides the data structure which is holding the runway 
instances and only provides access to it via a method. This is good 
design and allows you to change the underlying implementation as long as 
the interface is maintained. Your Lisp example exposes the list and 
makes it difficult for you to change it later. Lists are convenient data 
structures to represent a group of data that may change in size. Arrays 
are more efficient though. Considering that airports don't easily sprout 
new runways you are probably OK sticking with a fixed-size data 
structure such as a (non-adjustable) array for efficiency. In any case, 
hiding the implementation is still a better idea.


> [message-passing-vs-specialization-on-arguments discussion snipped]
> 
> What's this fascination with bashing Java? There is a reason I'm
> asking questions here and not in comp.lang.java. You needn't spend
> effort explaining to me that Lisp has a more general model.
> 
> I gave three examples, only one of them was Java, and only one an OO
> language. Neither C nor XPath are OO, but both navigate hierarchical
> structures left-to-right. In Java, a convention evolved to use methods
> for field access to protect these fields from unexpected
> modification. This attaches unnecessary functional semantics to the
> simple operation of dereferencing a variable. In particular, accessor
> methods in Java may have side effects (bad form to be sure, but
> possible). What bothered me about Lisp structures is that defstuct
> attaches the same functional semantics to this operation.
> 
> 

I'm at a loss to understand your defensive attitude here. I did not 
'bash' Java by any stretch of the imagination. I focused on your Java 
example since I haven't used C in awhile and I don't know what the hell 
XPath is...I simply pointed out that Lisp has a different approach to OO 
and what that entails. Please stop and take a moment to explain to me 
how you imagine your Java syntax would work with multiple dispatch.

>>I think many Lisp gurus would advise you to learn CLOS and avoid
>>DEFSTRUCT. See Peter's book, for example.
> 
> 
> As Luis Oliveira mentioned, Paul Graham seemed to advocate that
> approach in his /ANSI Common LISP/. That the book I've been working
> from.
> 
Once again you appear to be reading too much into my reply. What part of 
my statement triggered your defensiveness? I pointed out what I perceive 
to be the consensus view among more experienced (than I) Lispers. I 
didn't attack your approach. I agree that Paul Graham seems dismissive 
of CLOS, and I realize that he uses examples of structures in his book. 
That doesn't mean that he is in the majority. Now you know that many 
disagree with him on this point.

David Sletten
From: Gareth McCaughan
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <87wtx3kxgg.fsf@g.mccaughan.ntlworld.com>
Ari Krupnikov wrote:

> C:     anAirport.runways[0].highEnd.location.latitude
...
> (location-latitude
>   (rwy-end-location
>     (runway-high-end
>       (nth 0
>         (airport-runways
>           (an-airport))))))
...
> (latitude (location (high-end (nth 0 (runways (an-airport))))))
> 
> which still reads in the wrong direction.

Its wrongness is mostly a matter of familiarity.

But I think there *is* something genuinely more natural
about having temporal order correspond to reading order;
this applies to other functions besides accessors, but
most programming languages have function application syntax
basically the same as Lisp's. The obvious exceptions,
reverse-polish languages like Forth and PostScript, are
notoriously hard to read until one's very used to them,
considerably more so than Lisp; this is why I think it's
basically familiarity that makes the difference.

You could always do this:

    (defmacro chain (expr &rest transformers)
      (if (null transformers)
        expr
        (let ((head (first transformers))
              (tail (rest transformers)))
          (if (consp head)
            `(chain ,(subst expr '__ head) . ,tail)
            `(chain (,head ,expr) . ,tail)))))

and then

    (chain an-airport runways (nth 0 __) high-end location latitude)

Perhaps CHAIN isn't the best possible name. Anyway, I'd
advise you to spend a while longer getting used to Lisp;
if it still bothers you, then you can use something like
my macro above.

A word of caution about CHAIN. If you decide you like it
and ever find yourself wanting to use something like
(cons __ __) as one of the transformers, then you should
make a more sophisticated version of CHAIN that avoids
code duplication. This isn't difficult, but I'm deliberately
not doing it; you should avoid such things until you have
at least enough familiarity with Lisp that making the
necessary improvement to CHAIN is easy for you :-).

Something else you can do but shouldn't until you've spent
longer with the language to appreciate why it might be a
bad idea: you could define a read-macro to alter the
character-level syntax so that instead of the above you
could write

    [an-airport runways (nth 0 __) high-end location latitude]

This, too, is easy, and for the same reason as before I shan't
show you how to do it!

-- 
Gareth McCaughan
.sig under construc
From: K. Ari Krupnikov
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <86r7naldlh.fsf@deb.lib.aero>
Gareth McCaughan <················@pobox.com> writes:

> Ari Krupnikov wrote:
> 
> > C:     anAirport.runways[0].highEnd.location.latitude
> ...
> > (latitude (location (high-end (nth 0 (runways (an-airport))))))
> > 
> > which still reads in the wrong direction.
> 
> Its wrongness is mostly a matter of familiarity.

OK. I'll see if I can adjust to it :=)

> You could always do this:
> 
>     (defmacro chain (expr &rest transformers)
> 
>     [...]
> 
> and then
> 
>     (chain an-airport runways (nth 0 __) high-end location latitude)
> 
> Perhaps CHAIN isn't the best possible name.

PATH? My original example had much more XPath influence in it than C.
XPath, in turn, has the obvious Unix filepath connotations.

> Anyway, I'd advise you to spend a while longer getting used to Lisp;
> if it still bothers you, then you can use something like my macro
> above.

Right. It is not my habit to start working "around" a language before
I learn what the "proper" way of doing something is in that
language. That's why I'm asking these questions here :=)

> [read-macro suggestion snipped]
> 
> This, too, is easy, and for the same reason as before I shan't
> show you how to do it!

That's fair enough. I think I'm not even going to use the macro you
did include here for a while. Maybe I'll adjust to the "regular"
syntax. But I do appreciate your suggestion - I had the feeling that a
macro like that should be possible (I haven't yet written any macros
of my own), but I wasn't sure how good of an idea it was to use it.

Ari.

-- 
Elections only count as free and trials as fair if you can lose money
betting on the outcome.
From: Ray Dillinger
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <GjCkd.4605$_3.56073@typhoon.sonic.net>
Gareth McCaughan wrote:
> Ari Krupnikov wrote:
> 
> 
>>C:     anAirport.runways[0].highEnd.location.latitude
> 
> ...
> 
>>(location-latitude
>>  (rwy-end-location
>>    (runway-high-end
>>      (nth 0
>>        (airport-runways
>>          (an-airport))))))
> 
> ...
> 
>>(latitude (location (high-end (nth 0 (runways (an-airport))))))
>>
>>which still reads in the wrong direction.
> 
> 
> Its wrongness is mostly a matter of familiarity.
> 

It's a funny thing, but in scheme, we would just write:

(((nth (an-airport 'runways) 0) 'location) 'latitude)

Here (an-airport 'runways) returns an array of functions,
nth selects the zeroth member of the array which is called
with the symbol argument 'location and returns another
function; the function returned is then called with the
symbol argument 'latitude and returns the latitude of
that location.

The selectors-as-function-arguments pattern is fairly
strong in scheme, I think because it's a lisp-1 and
doesn't need any extra syntax for calling a function
that's returned from another function.

				Bear
From: Marco Antoniotti
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <KsLkd.13$E26.20725@typhoon.nyu.edu>
Ray Dillinger wrote:
> Gareth McCaughan wrote:
> 
>> Ari Krupnikov wrote:
>>
>>
>>> C:     anAirport.runways[0].highEnd.location.latitude
>>
>>
>> ...
>>
>>> (location-latitude
>>>  (rwy-end-location
>>>    (runway-high-end
>>>      (nth 0
>>>        (airport-runways
>>>          (an-airport))))))
>>
>>
>> ...
>>
>>> (latitude (location (high-end (nth 0 (runways (an-airport))))))
>>>
>>> which still reads in the wrong direction.
>>
>>
>>
>> Its wrongness is mostly a matter of familiarity.
>>
> 
> It's a funny thing, but in scheme, we would just write:
> 
> (((nth (an-airport 'runways) 0) 'location) 'latitude)
> 
> Here (an-airport 'runways) returns an array of functions,
> nth selects the zeroth member of the array which is called
> with the symbol argument 'location and returns another
> function; the function returned is then called with the
> symbol argument 'latitude and returns the latitude of
> that location.
> 
> The selectors-as-function-arguments pattern is fairly
> strong in scheme, I think because it's a lisp-1 and
> doesn't need any extra syntax for calling a function
> that's returned from another function.

It is because Scheme is a Lisp-1 and probably because Scheme lacks 
multimethods dispatching.

Apart from the annoying FUNCALL you could write all the above in CL.  Of 
course you have to assume that everything is a function that accepts a 
`message'.

Cheers
--
Marco





> 
>                 Bear
> 
From: Pascal Bourguignon
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <87zn1zxn1c.fsf@naiad.informatimago.com>
···@lib.aero (K. Ari Krupnikov) writes:
> [...]
> C:     anAirport.runways[0].highEnd.location.latitude

Use of such long strings is debatable...

> [...]
> (location-latitude
>   (rwy-end-location
>     (runway-high-end
>       (nth 0
>         (airport-runways
>           (an-airport))))))
> 
> I found this difficult to read, for two reasons. 

> Both of them seem to
> stem from the fact that Lisp uses functions to access structure slots,
> as opposed to some dedicated mechanism. 

What makes you think that there is not a dedicated mechanism?

The notation for both functions, macros, and special operators in lisp
is always the same: (<op> <arg>...)

This is a very powerful notation, for it allow the programmer to
manipulate easily his programs.  But the lisp system doesn't implement
all of them the same way. (*)



> First, the order is reversed:
> I tend to think of trees (including nested lists in Lisp) as
> originating at top left corner of my screen and growing right and
> down; my Lisp expression above goes in the opposite direction -- the
> root, "an-airport" is at the right bottom of my expression. 

What is the most important? If it's the latitude, then it should
appear first.  If it's the airport, why are you walking down this
path?  Abstract and write: (do-something-with-airport an-airport)


> Second,
> the long function names that include type names make expressions much
> longer and less readable. I could solve the second problem by using
> :conc-name nil or, I imagine, by defining accessors as CLOS
> methods[1]. In this case, the expression would become
> 
> (latitude (location (high-end (nth 0 (runways (an-airport))))))
> 
> which still reads in the wrong direction.
> 
> Is this just a temporary difficulty adjusting to Lisp, and being able
> to reverse accessor lists is simply a skill that comes with
> experience, or am I missing a better Lisp way to organize hierarchical
> data?

Compare:

anAirport.runways[0].highEnd.location.latitude

(latitude (location (high-end (nth 0 (runways (an-airport))))))

The latitude of the location of the high-end of the zeroth runways of
an airport.

You could further abstract, teaching your program that the latitude of
a end is that of the location of that end, and that runways of
airports are numbered, so you would write:

    (latitude (high-end (runway an-airport 0)))


Now, just in case you really have a lot of such strings to write and
the expression of the problem/solution would really be clearer if you
wrote them:

(defun embed-calls (args)
   (cond
      ((null (cdr args))  (car args))
      ((listp (car args)) (APPEND (car args) (list (embed-calls (cdr args)))))
      (t                  (list   (car args) (embed-calls (cdr args))))))

(DEFMACRO rcc (&rest args) (embed-calls (REVERSE args)))

So you can just write: 

    (rcc airport runways (nth 0) high-end location latitude)

and get the meaning you want:

(macroexpand-1 '(rcc airport runways (nth 0) high-end location latitude))
==> (LATITUDE (LOCATION (HIGH-END (NTH 0 (RUNWAYS AIRPORT)))))


> [1] I decided to first learn "straight" CL without CLOS -- is that a
> reasonable approach?

Mu.

(I decided to first learn anatomy without consideration for the
muscles -- is that a reasonable approach?)


------------------------------
(*) For example:

CL-USER> (disassemble (compile nil (lambda (x) (car x))))

Disassembly of function NIL
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
3 byte-code instructions:
0     (LOAD 1)
1     (CAR)          <=== This is a micro-instruction of this virtual-machine!
2     (SKIP&RET 2)
NIL


CL-USER> (disassemble (compile nil (lambda (x) (runways x))))

WARNING :
Function RUNWAYS is not defined

Disassembly of function NIL
(CONST 0) = RUNWAYS
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
3 byte-code instructions:
0     (LOAD&PUSH 1)
1     (CALL1 0)  ; RUNWAYS  <=== A function call (normal or generic-function)
3     (SKIP&RET 2)
NIL


CL-USER> (disassemble (compile nil (lambda (x) (nth 0 x))))

Disassembly of function NIL
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
3 byte-code instructions:
0     (LOAD 1)
1     (CAR)        <=== See! (nth 0 x) is compiled as a (CAR) primitive.
2     (SKIP&RET 2)
NIL
CL-USER> 

-- 
__Pascal Bourguignon__
From: Szymon
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <87pt2v5h60.fsf@eva.rplacd.net>
···@lib.aero (K. Ari Krupnikov) writes:

> [.....]

> C:     anAirport.runways[0].highEnd.location.latitude
> 
> Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()
> 
> XPath: $anAirport/runway[1]··················@latitude
> 
> This is a simplification of an actual application I'm working
> with. The examples imply straightforward structures in their
> respective languages. What should be the Lisp equivalent?
> 
> My first attempt was to define a bunch of structures:
> 
> (location-latitude
>   (rwy-end-location
>     (runway-high-end
>       (nth 0
>         (airport-runways
>           (an-airport))))))

My proposition:


(airport :runway 0 :high-end :latitude)


;; ----------------------------------
;; --------------- example (skeleton)

(defun make-airport (....)
  (let ((runway    (list/or/vector_of_closures))
        (closet    (...))
        (office    (...))
        (weaponary (...))
        (...       (...))
        (...       (...)))
    (lambda (object object-index &rest params) ;; airport closure.
      (case object
         (:runway (apply (nth object-index runway) params))
         (:closet .....)
         (.............))
      ..............)
    .................))
;; ----------------------------------

Regards, Szymon.
From: Thomas A. Russ
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <ymi654m8zrw.fsf@sevak.isi.edu>
···@lib.aero (K. Ari Krupnikov) writes:


>  In this case, the expression would become
> 
> (latitude (location (high-end (nth 0 (runways (an-airport))))))
> 
> which still reads in the wrong direction.
> 
> Is this just a temporary difficulty adjusting to Lisp, and being able
> to reverse accessor lists is simply a skill that comes with
> experience, or am I missing a better Lisp way to organize hierarchical
> data?

This is a temporary difficulty in adjusting to Lisp.  After a while you
get used to having nested function calls.  I would imagine that some of
my Java code would look a bit funny to other programmers, since I will
often do more nesting of calls than one would normally see.

If you find yourself doing particular deep accesses regularly, then it
may be well worth designing some special purpose accessors.  For
example, something like:

(defun get-runway-ends (airport n)
  (let ((runway (nth n (runways airport))))
    (values (low-end runway) (high-end runway))))

Then your expression becomes

   (multiple-value-bind (low high) (get-runway-ends an-airport 0)
     (latitude low)
     (longitude low)
     (latitude high)
     (longitude high)
     ...)

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Wade Humeniuk
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <175id.49079$E93.6583@clgrps12>
K. Ari Krupnikov wrote:

> 
> Is this just a temporary difficulty adjusting to Lisp, and being able
> to reverse accessor lists is simply a skill that comes with
> experience, or am I missing a better Lisp way to organize hierarchical
> data?

It is just a temporary dificutlty.  Up/down, left/right, there are no
absolute right or wrong with these relative value judgments.  Things
will go a lot easier when you do not fret about them and just use the
language as is.

That said, I think that the Lisp order is a better a match for the english
version "The latitude of the high end of YYC's runway 554". Of course
the Lisp code has to be more rigourous, but that is because computer
languages are so pedantic.

The code

(latitude (high-end (runway yyc 554))

seems sufficient to mean what you want.  With your data structures
you would have to write the functions (probably methods)
runway, high-end and latitude.  Also one of things about Lisp is not
to worry that access is by function.  Its more important to write what
you mean  (in Lisp syntax) and not fret how it is done.  Just be
be clear and expressive.  Most other computer languages force you
to worry about "how" things are actually implemented, but the how
and the what are split up in Lisp.  You learn to
trust that the "how" can be discovered (and implemented)
after you express what needs to be done.

My other advice is try to be "speak" when writing your Lisp code.  Make it
conversational, do not try to force forms onto it.

Wade
From: Szymon
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <87lldj5aok.fsf@eva.rplacd.net>
(let ((runway-1
       (make-runway '(:high-end (:latitude 15) (:longitude 20))
                    '(:low-end  (:latitude 0)  (:longitude 10))))
      (runway-2
       (make-runway '(:high-end (:latitude 30) (:longitude 0))
		    '(:low-end  (:latitude 10) (:longitude 60)))))
  (make-airport 'airport-1 runway-1 runway-2))



CL-USER> (airport-1 :runway 0 :high-end :latitude)

15


CL-USER> (airport-1 :runway 1 :low-end :longitude)

60


;;; --------------------------------------------------------------

(defun make-runway (&rest inits)
  (let ((props (make-hash-table)))
    (mapc (lambda (pair) (setf (gethash (car pair) props) (cdr pair))) inits)
    (lambda (key1 key2 &key set print-all)
      (block nil
	(when set
	  (setf (cadr (assoc key2 (gethash key1 props))) set)
	  (return))
	(when print-all
	  (maphash (lambda (&rest x) (apply #'format t "~A ~{~A ~}~%" x)) props)
	  (return))
	(cadr (assoc key2 (gethash key1 props)))))))
;;
;; examples:
;;
;; CL-USER> (make-runway '(:high-end (:latitude 0) (:longitude 0))
;;                       '(:low-end  (:latitude 0) (:longitude 0)))
;;
;; CL-USER> (setq example-runway *)
;;
;; CL-USER> (funcall example-runway nil nil :print-all t)
;;
;; HIGH-END (LATITUDE 0) (LONGITUDE 0) 
;; LOW-END  (LATITUDE 0) (LONGITUDE 0) 
;;
;; CL-USER> (funcall example-runway :high-end :latitude :set 55.5)
;;
;; CL-USER> (funcall example-runway nil nil :print-all t)
;;
;; HIGH-END (LATITUDE 55.5) (LONGITUDE 0) 
;; LOW-END  (LATITUDE    0) (LONGITUDE 0) 
;;
;; CL-USER> (funcall example-runway :high-end :latitude)
;;
;; 55.5

;;; --------------------------------------------------------------

(defun make-airport (airport-name &rest runways)
  (setf (symbol-function airport-name)
	(let ((runway (copy-list runways)))
	  (lambda (object object-index &rest params)
	    (case object
	      (:runway (apply (nth object-index runway) params))))))
  nil)

;;; --------------------------------------------------------------

Regards, Szymon.

ps. Don't take this too seriously, use CLOS (or maybe embedded prolog).
From: Kenny Tilton
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <J86id.115057$Ot3.105618@twister.nyc.rr.com>
K. Ari Krupnikov wrote:

> In my attempts to transition to Lisp, I'm having a hard time
> organizing my data in hierarchical structures. In every language I've
> used so far, hierarchical data structures are useful abstractions for
> dealing with complexity. Different languages have different ways of
> defining these structures (structures in C, classes in Java, elements
> in XML), but the way one navigates to a datum is essentially similar:
> 
> C:     anAirport.runways[0].highEnd.location.latitude
> 
> Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()
> 
> XPath: $anAirport/runway[1]··················@latitude
> 
> This is a simplification of an actual application I'm working
> with. The examples imply straightforward structures in their
> respective languages. What should be the Lisp equivalent?
> 
> My first attempt was to define a bunch of structures:
> 
> (location-latitude
>   (rwy-end-location
>     (runway-high-end
>       (nth 0
>         (airport-runways
>           (an-airport))))))
> 
> I found this difficult to read, for two reasons.

As Barry says, the order of functions in the code you posted on 
comp.lang.lisp on the Internet seems fine to me. :)

Also, the example is not a good one because I doubt real code ever 
navigates so far in one go; functional decomposition should lead to 
two-step navigations, three at most. This may seem like a quibble, but I 
think sometimes extreme examples lead to mistaken impressions.


> Both of them seem to
> stem from the fact that Lisp uses functions to access structure slots,
> as opposed to some dedicated mechanism.

Exactly, and that is a huge win for CL. In C, one does get this same 
ordering: coefficient( highOrderTerm ( thisPolynomial ) )

But when they bolted on objects, they created some new 
punctuation-enabled syntax. That is how the language is designed ("hey! 
lets use ····@*!") so it seems normal. But normal in Lisp means 
"everything (except read macros) is (<operator> <operand> ....), and 
they did not break that to handle OO. All I am saying here is that, even 
if you hate the ordering, it keeps Lisp simpler to not create special 
chaining syntax.

> (latitude (location (high-end (nth 0 (runways (an-airport))))))
> 
> which still reads in the wrong direction.

Another point is that, in reading the code, I will see that expression 
and wonder what it is /in the context of the code/, which seems to be 
trying to take off. Chances are I will see "latitude" and not need to 
read the rest ("ok, I did not screw up and use the longitude") -- by the 
time I get to the latitude being used, other code will likely have 
picked a runway or even the end of the runway. So I think having the 
specific component first makes sense.


> 
> Is this just a temporary difficulty adjusting to Lisp

I think so.

kt
From: R. Mattes
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <pan.2004.11.03.22.06.16.207840@mh-freiburg.de>
On Wed, 03 Nov 2004 14:43:53 +0000, Kenny Tilton wrote:

> 
> 
> K. Ari Krupnikov wrote:
> 
>> In my attempts to transition to Lisp, I'm having a hard time
>> organizing my data in hierarchical structures. In every language I've
>> used so far, hierarchical data structures are useful abstractions for
>> dealing with complexity. Different languages have different ways of
>> defining these structures (structures in C, classes in Java, elements
>> in XML), but the way one navigates to a datum is essentially similar:
>> 
>> C:     anAirport.runways[0].highEnd.location.latitude
>> 
>> Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()
>> 
>> XPath: $anAirport/runway[1]··················@latitude
>> 
>> This is a simplification of an actual application I'm working
>> with. The examples imply straightforward structures in their
>> respective languages. What should be the Lisp equivalent?
>> 
>> My first attempt was to define a bunch of structures:
>> 
>> (location-latitude
>>   (rwy-end-location
>>     (runway-high-end
>>       (nth 0
>>         (airport-runways
>>           (an-airport))))))
>> 
>> I found this difficult to read, for two reasons.
> 

As others have said, this actually reflects (western) spoken languages.
In SL this is actually saving a lot of bandwidth since often the context
of the conversation lets one skip the innermost layers. When you talk
about a specific airport and maybe even a specific runway you might get
away with saying "the end-location of the high-end". Since this is so
"natural" and convenient some algolish languages have some syntactic 'WITH ...'
sugar:
 
 WITH fo
   WITH bar 
     DO ...
   END 
 END

CL does provide this as well for cases where these "contextual" objects
are used often. Maybe it's worth taking the time to write some makro
WITH-AIRPORT / WITH-RUNWAY etc. Or even a domain specific language:

 (the rwy-end-location of 
   (the runway-high-end of 
    (the (nth 0 airport-runwy) of an-airport)))

> Also, the example is not a good one because I doubt real code ever
> navigates so far in one go; functional decomposition should lead to
> two-step navigations, three at most. This may seem like a quibble, but I
> think sometimes extreme examples lead to mistaken impressions.

...and to less-than-professional code, if i might add :-)
Every once in a while i come across code like this:
 
 $foo.bar{'glup'}[3].move()

all fine _unless_ there's no $foo.bar{'glup'}[3]. Thn you end up calling
a method of a non-existing object. Bad.
Functional decomposition (or, even worse, functional/structured data
decomposition as is the case in Perl/Python et. al.) makes proper error
handling pretty hard ...

> 
>> Both of them seem to
>> stem from the fact that Lisp uses functions to access structure slots,
>> as opposed to some dedicated mechanism.
> 
> Exactly, and that is a huge win for CL. In C, one does get this same
> ordering: coefficient( highOrderTerm ( thisPolynomial ) )

Hmm, afaik Lisp _does_ use "some dedicated mechanism" to access slots -
that's one of the motivations behind MOP - providing efficient slot
access in cases where this is possible. Or does the OP talk about the
_syntax_ for slot access?

> 
> 
>> Is this just a temporary difficulty adjusting to Lisp
> 
> I think so.

Hope so

 Ralf Mattes  
> kt
From: Peter Seibel
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <m3wtx23kdv.fsf@javamonkey.com>
···@lib.aero (K. Ari Krupnikov) writes:

> In my attempts to transition to Lisp, I'm having a hard time
> organizing my data in hierarchical structures. In every language
> I've used so far, hierarchical data structures are useful
> abstractions for dealing with complexity. Different languages have
> different ways of defining these structures (structures in C,
> classes in Java, elements in XML), but the way one navigates to a
> datum is essentially similar:
>
> C:     anAirport.runways[0].highEnd.location.latitude
>
> Java:  anAirport.getRunway(0).getHighEnd().getLocation().getLatitude()
>
> XPath: $anAirport/runway[1]··················@latitude
>
> This is a simplification of an actual application I'm working with.
> The examples imply straightforward structures in their respective
> languages. What should be the Lisp equivalent?

Wade posted a similar suggestion but I'll flesh it out a bit:

  (lattitude (high-end (runway 0 *an-airport*)))

Which might be made to work like this (untested):

  (defclass airport ()
    (runways :reader runways :initform (make-hash-table)))

  (defclass runway ()
    (high-end :accessor high-end :initarg :high-end)
    (low-end :accessor low-end :initarg :low-end))

  (defclass location ()
    (longitude :accessor longitude :initarg :longitude)
    (lattitude :accessor lattitude :initarg :lattitude))

  (defmethod add-runway (airport id runway)
    (setf (gethash id (runways airport)) runway))

  (defmethod runway (id airport)
    (gethash number (runways airport)))

  (defvar *an-airport* (make-instance 'airport))

  (add-runway *an-airport*
    (make-instance 
      'runway
      :high-end (make-instance 'location :longitude 10.1 :lattitude 20.0)
      :low-end (make-instance 'location :longitude 10.2 :lattitude 20.1)))

If you really need a separate class to represent the end of a runway,
you can define it and mix in the location class:

  (defclass runway-end (location)
    (... other slots ...))

and then build runway objects like this:

  (make-instance 
    'runway
    :high-end (make-instance 'runway-end :longitude 10.1 :lattitude 20.0)
    :low-end (make-instance 'runway-end :longitude 10.2 :lattitude 20.1)))

and the method on LATTITUDE specialized on location will also apply to
runway location.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Alan Crowe
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <86sm7q1z9j.fsf@cawtech.freeserve.co.uk>
Ari Krupnikov wrote 
> I could solve the second problem by using :conc-name nil
> or, I imagine, by defining accessors as CLOS methods[1].

Defining accessors as CLOS methods works well.

CL-USER(1): (defstruct 2d x y)
CL-USER(2): (defstruct 3d x y z)
CL-USER(3): (defparameter *s1* (make-2d :x 3 :y 6))
CL-USER(4): (defparameter *v1* (make-3d :x 30 :y 60 :z 70))
CL-USER(6): (defparameter *thing*
	      (case (random 2)
		(0 *s1*)
		(1 *v1*)))

How do we get at the x component of our thing?

CL-USER(7): (typecase *thing*
	      (2d (2d-x *thing*))
	      (3d (3d-x *thing*)))
30

Well, OK, but

CL-USER(8): (defmethod x ((o 2D)) (2d-x o))
CL-USER(9): (defmethod x ((o 3d)) (3d-x o))
CL-USER(10): (x *thing*)
30

That is much nicer.

Ari Krupnikov also asked
> [1] I decided to first learn "straight" CL without CLOS --
> is that a reasonable approach?

Yes, but you've already progressed beyond that stage. I say
that for three reasons.

1) You are already using :conc-name and realise that you can
   use methods as accessors.

2) You can get started with CLOS by defining methods on
   structures. From the hyperspec

	4.3.7 Integrating Types and Classes

	Each structure type created by defstruct without
	using the :type option has a corresponding
	class. This class is a generalized instance of the
	class structure-class. The :include option of
	defstruct creates a direct subclass of the class
	that corresponds to the included structure type.

   So you can play defmethod for an hour before moving on to defclass.

3) Old hands look at CLOS,  and say: Multiple inheritance,
   multiple dispatch, fully dynamic, difficult stuff.

   And they are right. If you want to /implement/ CLOS with
   reasonable efficiency, these are indeed difficult
   features.

   But you want to /use/ an existing implementation of
   CLOS. So you just ignore multiple stuff until you need
   it. Later, when you try it, it just works. From your
   perspective CLOS is especially simple, because you never
   have to learn how to work around the limitations of
   single inheritance and the message passing model.

Ari Krupnikov also wrote:
> ... Lisp uses functions to access structure slots, as
> opposed to some dedicated mechanism.

That is not quite right. You are over-interpreting the
surface syntax. The compiler is perfectly capable of
recognising (2d-x *s1*) as accessing a slot in a structure,
and emitting efficient code. It would be more accurate to
say:
 
  Lisp uses the same surface syntax for both function calls
  and accessing structure slots.

You really want this feature. 

Consider a point represented in Cartesian coordinates, with
functions to compute the radius and angle for polar
coordinates. Once the program is running on real data you
might find that you would be better off storing the polar
form and computing x and y on the odd occassion when they
are needed. You don't want to have to go through your code
changing from a slot access notation to a function notation.

More generally, you do not want the syntax to expose the
difference between slot access and function call, because it
ties your hands when it comes to changing the representation
of your data structures.

CLOS handles this very well. For example there is a
:default-initargs class option, which gives you an extra
place to put your initforms if you abolish the slots they
used to initialise.

Alan Crowe
Edinburgh
Scotland
From: Barry Margolin
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <barmar-9B78EE.20394703112004@comcast.dca.giganews.com>
In article <··············@deb.lib.aero>,
 ···@lib.aero (K. Ari Krupnikov) wrote:

> In this case, the expression would become
> 
> (latitude (location (high-end (nth 0 (runways (an-airport))))))
> 
> which still reads in the wrong direction.

BTW, if you think this is bad, be glad you didn't learn Lisp in the days 
of Flavors.  Then it would have been:

(send (send (send (nth 0 (send an-airport :runways)) 
                  :high-end) :location) :lattitude)

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Rahul Jain
Subject: Re: newbie: hierarchies in lisp? (long)
Date: 
Message-ID: <873bzq40jq.fsf@nyct.net>
···@lib.aero (K. Ari Krupnikov) writes:

> (latitude (location (high-end (nth 0 (runways (an-airport))))))
>
> which still reads in the wrong direction.

"The latitude of the location of the high end of the 0th runway of an
airport."

> [1] I decided to first learn "straight" CL without CLOS -- is that a
> reasonable approach?

If you don't want to learn about easy polymorphism or inheritance of
functionality/composition, sure. If you do want it, learn about it... 
Same with any other feature of CL. You can ignore the bits on defining
read macros if you really don't care to optimize your syntax that much.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist