Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lisp style question

56 views
Skip to first unread message

Katalin Sinkov

unread,
Dec 2, 2010, 3:33:18 AM12/2/10
to
I have recently taken up programming in lisp.

In the {} world I would return a small table like

width 1
height 2
weight 3

from a function using a pointer to a structure.

the structure members would be accessed by a dot notation of
membership.

What are various elegant methods to do this in lisp ?

I can basically do it crudely using the lowest level car , cdr and
make a list of pairs to return this data.

( (x1 y1) (x2 y2) (x3 y3) )

with the usual right associativity ie ( a b c d ) = (a (b (c (d)..)

and write a function

(defun value (key)
""
..........
)


Any style suggestions ?

Katalin

Paul Rubin

unread,
Dec 2, 2010, 3:46:00 AM12/2/10
to
Katalin Sinkov <lisps...@gmail.com> writes:
> width 1
> height 2
> weight 3
> the structure members would be accessed by a dot notation of
> membership.
>
> What are various elegant methods to do this in lisp ?

The corresponding idea would be defstruct or defclass

> I can basically do it crudely using the lowest level car , cdr and
> make a list of pairs to return this data.

You could do that for a situation where defstruct or defclass would be
too heavyweight.

Frode V. Fjeld

unread,
Dec 2, 2010, 3:50:55 AM12/2/10
to
Katalin Sinkov <lisps...@gmail.com> writes:

> In the {} world I would return a small table like
>
> width 1
> height 2
> weight 3

Typically in Lisp you'd return either a property or association list.

I.e: (WIDTH 1 HEIGHT 2 WEIGHT 3) with accessor GETF,

or ((WIDTH . 1) (HEIGHT . 2) (WEIGHT . 3)) with accessor ASSOC.

--
Frode V. Fjeld

Captain Obvious

unread,
Dec 2, 2010, 4:15:09 AM12/2/10
to
KS> What are various elegant methods to do this in lisp ?

defclass/defstruct, alist, plist or values.

As people have already mentioned other approaches, I'll comment on values:

You can return multiplt values from a function directly. Typically you can
consider using this:
* when there is fixed number of values being returned
* caller would immediately want to use these values rather store them for
later use
* some of values returned are optional

Here's how to do this:

Function which returns multiple values:

(defun get-object-properties (...)
"returns (values width height weight)"
(let ((width ...)
(height ...)
(weight ...)
(values width height weight))

Function which uses multiple values:

(defun test ()
(multiple-value-bind (width height weight)
(get-object-properties ...)

(print width)
(print height)
(print weight)))


As you see, with multiple-value-bind values go directly to local variables.
Sometimes it is convenient. It is also good from performance perspective
because compiler can optimize this so it doesn't allocate space on heap.

If you're not interested in weight you can write

(multiple-value-bind (width height)
(get-object-properties ...)
...)

It still works, no need to match number of values.

If you're only interested in primary value you can just call it directly
e.g.
(print (get-object-properties ...))
It will print width.

Pascal J. Bourguignon

unread,
Dec 2, 2010, 10:42:55 AM12/2/10
to
Katalin Sinkov <lisps...@gmail.com> writes:


If the set of rows is fixed (it's alwaays a width, a height and a
weight), then you could use a structure:

(defstruct volume
width height weight)

(make-volume :width 1 :height 2 :weight 3)


On the other hand if your function generate dynamic tables (tables whose
rows are not known until run-time), then you can use a-list or p-list.

(let ((p-list (list :width 1 :height 2 :weight 3))
(a-list (list (cons :width 1) (cons :height 2) (cons :weight 3))))

(or p-list a-list)) ;-)


If you have a lot more than ten or thirty rows (and the order doesn't
matter, but quick access to one specific row matters), you may use a
hash table.

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Katalin Sinkov

unread,
Dec 2, 2010, 8:11:06 PM12/2/10
to
On Dec 2, 12:50 am, "Frode V. Fjeld" <fr...@netfonds.no> wrote:

Of all the four or five replies, I found yours most helpful although
brief. This is perhaps due to me being a beginner, although the
replies seem very promising and I am desirous of understanding them. I
have just read the paper by McCarthy and the micro manual.

assoc. and pair. are the most elementary of the functions, although
not primitive and used in evaluator for working the symbol table.

but beyond this, i could not understand your post.

what is an "assoc list" and "a property list" and their difference ?

what is "setf" and how to write it in terms of the elementary
functions, car/cdr/cons/quote/cond/atom/eq ?

how to conveniently costruct the list that goes with getf ?

Presently I use the emacs IDE only and restricted to elisp, though i
can (require 'cl) so what are
the correponding operation in elisp ?

what are the corresponding functions to defclass/defstruct in elisp ?
I assume people are assuming CL.

Could you comment a little on the post of Captain Obvious and Pascal
Bourguignon ?

The former has "values" and the latter has "make-volume" and colons.
How did the constructor "make-volume" come to be ?

Is it a feature in elisp ?

Thanks for your help.

Katalin

Pascal J. Bourguignon

unread,
Dec 3, 2010, 12:22:30 AM12/3/10
to
Katalin Sinkov <lisps...@gmail.com> writes:

> On Dec 2, 12:50 am, "Frode V. Fjeld" <fr...@netfonds.no> wrote:
>> Katalin Sinkov <lispstyl...@gmail.com> writes:
>> > In the {} world I would return a small table like
>>
>> > width   1
>> > height  2
>> > weight  3
>>
>> Typically in Lisp you'd return either a property or association list.
>>
>> I.e: (WIDTH 1 HEIGHT 2 WEIGHT 3) with accessor GETF,
>>
>> or ((WIDTH . 1) (HEIGHT . 2) (WEIGHT . 3)) with accessor ASSOC.
>>
>> --
>> Frode V. Fjeld
>
> Of all the four or five replies, I found yours most helpful although
> brief. This is perhaps due to me being a beginner, although the
> replies seem very promising and I am desirous of understanding them. I
> have just read the paper by McCarthy and the micro manual.
>
> assoc. and pair. are the most elementary of the functions, although
> not primitive and used in evaluator for working the symbol table.
>
> but beyond this, i could not understand your post.
>
> what is an "assoc list" and "a property list" and their difference ?


It is expected from you that you can use google to find the definitions
of the terms used in our responses.

We won't redefine and re-explain everything for the millionth time, when
it's the most basic thing.

If you used google, eg. to search: a-list lisp
or: p-list lisp
you'd find the "GNU Emacs Lisp Reference Manual" which explains them,
amongst a lot of other references.

In addition to the "GNU Emacs Lisp Reference Manual", you may want to
read a more comprehensive lisp book, such as "Practical Common Lisp" or
"Common Lisp: a Gentle Introduction to Symbolic Computation". You may
also read the little book "Basic Lisp Techniques" (100 pages). And for
Common Lisp, you may consult the Common Lisp HyperSpec Reference.
Again, I won't provide the URLs, use Google.


> what is "setf" and how to write it in terms of the elementary
> functions, car/cdr/cons/quote/cond/atom/eq ?
>
> how to conveniently costruct the list that goes with getf ?
>
> Presently I use the emacs IDE only and restricted to elisp, though i
> can (require 'cl) so what are
> the correponding operation in elisp ?

Do (require 'cl). It would be silly not to. Put it at the beginning
of your ~/.emacs file.

Learn how to use emacs to get documentation about the lisp operators.
Command such as apropos, describe-function (C-h f), describe-variable
(C-h v), etc.

> what are the corresponding functions to defclass/defstruct in elisp ?
> I assume people are assuming CL.

defclass and defstruct.


For defclass, you will have to (require 'eieio), which, starting from
emacs 23 is included in the distribution.

> Could you comment a little on the post of Captain Obvious and Pascal
> Bourguignon ?

No, I won't comment on my posts. And if you wanted to address only
Frode, you should have sent him an email. (But personnaly, I answer
with much less priorioty to personal emails following up a usenet news
message, the less so when it can be of general interest.

> The former has "values" and the latter has "make-volume" and colons.
> How did the constructor "make-volume" come to be ?

Read the documentation of defstruct.

Erik Winkels

unread,
Dec 3, 2010, 7:59:32 AM12/3/10
to
On 2010-12-03, Katalin Sinkov <lisps...@gmail.com> wrote:
> On Dec 2, 12:50 am, "Frode V. Fjeld" <fr...@netfonds.no> wrote:
>> Katalin Sinkov <lispstyl...@gmail.com> writes:
>> > In the {} world I would return a small table like
>>
>> > width   1
>> > height  2
>> > weight  3
>>
>> Typically in Lisp you'd return either a property or association list.
>>
>> I.e: (WIDTH 1 HEIGHT 2 WEIGHT 3) with accessor GETF,
>>
>> or ((WIDTH . 1) (HEIGHT . 2) (WEIGHT . 3)) with accessor ASSOC.
>
> Of all the four or five replies, I found yours most helpful although
> brief. This is perhaps due to me being a beginner, although the
> replies seem very promising and I am desirous of understanding them. I
> have just read the paper by McCarthy and the micro manual.
>
> assoc. and pair. are the most elementary of the functions, although
> not primitive and used in evaluator for working the symbol table.
>
> but beyond this, i could not understand your post.

I'm very fond of using plists when exploratory programming and find
alists to be a little more verbose. Here's a small example (I always
use keywords as indicators: they stand out a little more and avoid
package troubles):

CL-USER(2): (defun plist-example (width height weight)
(list :width width :height height :weight weight))
PLIST-EXAMPLE

CL-USER(3): (defparameter plist (plist-example 1 2 3))
PLIST

CL-USER(4): plist
(:WIDTH 1 :HEIGHT 2 :WEIGHT 3)

CL-USER(5): (getf plist :height)
2

CL-USER(6): (setf (getf plist :height) 4)
4

CL-USER(8): plist
(:WIDTH 1 :HEIGHT 4 :WEIGHT 3)

Don Geddis

unread,
Dec 4, 2010, 7:05:27 PM12/4/10
to
Katalin Sinkov <lisps...@gmail.com> wrote on Thu, 2 Dec 2010 :
> what is "setf" and how to write it in terms of the elementary
> functions, car/cdr/cons/quote/cond/atom/eq ?

Unlike your subject line, this is no longer a "lisp style" question.

You just don't know lisp.

That's fine, but before asking "style" questions, you ought to learn
some lisp. Get an introductory tutorial (there are good free ones
online!), try some examples. After you learn a bit of lisp, and can
write simple programs, perhaps then you can come back with some style
questions.

Oh, and by the way: the functions your listed are not "the elementary
functions" (lisp has lots of functions, and there is no unique
elementary subset); nor can SETF be written in terms of the ones you
listed.

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
You see, wire telegraph is a kind of a very, very long cat. You pull his tail
in New York and his head is meowing in Los Angeles. Do you understand this?
And radio operates exactly the same way: you send signals here, they receive
them there. The only difference is that there is no cat.
-- Albert Einstein, when asked to describe radio

kenny

unread,
Dec 4, 2010, 7:42:49 PM12/4/10
to

(defstruct (it (:conc-name hic.)) cup)

(hic.cup (make-it :cup 'double))

HK

Katalin Sinkov

unread,
Dec 5, 2010, 1:22:31 PM12/5/10
to
On Dec 4, 4:05 pm, Don Geddis <d...@geddis.org> wrote:

> Katalin Sinkov <lispstyl...@gmail.com> wrote on Thu, 2 Dec 2010 :
>
> > what is "setf" and how to write it in terms of the elementary
> > functions, car/cdr/cons/quote/cond/atom/eq ?
>
> Unlike your subject line, this is no longer a "lisp style" question.

> That's fine, but before asking "style" questions, you ought to learn


> some lisp. Get an introductory tutorial (there are good free ones
> online!), try some examples. After you learn a bit of lisp, and can
> write simple programs, perhaps then you can come back with some style
> questions.

OK, I read the papers by McCarthy and the evaluator.

> You just don't know lisp.

Do you know lisp ? Do you even know how to fork off another thread if
that is your issue with the heading ? Also, style cannot be decoupled
from skill of language. Even if you learnt all the C, you could not
write a C++ style virtual class in it unless you had the skill. The
most you would be able to achieve would be methods with function
pointers.

> Oh, and by the way: the functions your listed are not "the elementary
> functions" (lisp has lots of functions, and there is no unique
> elementary subset); nor can SETF be written in terms of the ones you
> listed.

But you have one set provided to you on silver plate to use. Must I
provide you with all of them before you will activate your neuron and
lift your finger to explain how setf is implemented ?

HTH

> -- Don
> ___________________________________________________________________________­____

Pascal J. Bourguignon

unread,
Dec 5, 2010, 1:40:51 PM12/5/10
to
Katalin Sinkov <lisps...@gmail.com> writes:

You don't seem to know how to fork a new thread either. I'm somewhat
reluctant to answer to this setf question, in a thread that seems to
have turned to a personal flamewar.

Tim Bradshaw

unread,
Dec 5, 2010, 2:19:49 PM12/5/10
to
On 2010-12-05 18:22:31 +0000, Katalin Sinkov said:
>
> But you have one set provided to you on silver plate to use. Must I
> provide you with all of them before you will activate your neuron and
> lift your finger to explain how setf is implemented ?

You may not realise that you're doing is something like saying "here's
the instruction set of a PDP-11, now explain to me, in terms of those
instructions, how the virtual memory system in Solaris 10 works". Even
if it could be done, the answer would not be informative.

(Well, of course, what you're actually doing is alienating everyone,
but I assume that is intentional, though I don't pretend to understand
why, or why this disease is so common.)

RG

unread,
Dec 5, 2010, 3:51:00 PM12/5/10
to
In article
<6e2fe51c-ff4c-429f...@n2g2000pre.googlegroups.com>,
Katalin Sinkov <lisps...@gmail.com> wrote:

> On Dec 2, 12:50 am, "Frode V. Fjeld" <fr...@netfonds.no> wrote:
> > Katalin Sinkov <lispstyl...@gmail.com> writes:
> > > In the {} world I would return a small table like
> >
> > > width   1
> > > height  2
> > > weight  3
> >
> > Typically in Lisp you'd return either a property or association list.
> >
> > I.e: (WIDTH 1 HEIGHT 2 WEIGHT 3) with accessor GETF,
> >
> > or ((WIDTH . 1) (HEIGHT . 2) (WEIGHT . 3)) with accessor ASSOC.
> >
> > --
> > Frode V. Fjeld
>
> Of all the four or five replies, I found yours most helpful although
> brief. This is perhaps due to me being a beginner, although the
> replies seem very promising and I am desirous of understanding them. I
> have just read the paper by McCarthy and the micro manual.

There's another solution that doesn't seem to have been mentioned yet:

? (defstruct thing width height weight)
THING
? (setf thing (make-thing :width 1 :height 2 :weight 3))
#S(THING :WIDTH 1 :HEIGHT 2 :WEIGHT 3)
? (thing-height thing)
2
? (slot-value thing 'height)
2

> what is an "assoc list" and "a property list" and their difference ?

The difference is purely one of convention. Both are simple
arrangements of cons cells, but an association list (also called an
assoc list of an a-list) looks like this:

((key . value) (key . value) ...)

while a property list (also called a p-list) looks like this:

(key value key value ...)

These are not the only ways to create associative maps using cons cells.
For example, there is a little-used convention that I call a D-List (for
"dissociated association list") that looks like this:

((key key ...) value value ...)

The advantage of a D-List is that multiple D-List can share the same set
of keys so if you have a lot of associative maps with the same keys this
can be a big performance win. There are lots of other efficiency hacks
you can do on D-Lists that you can't do on A-Lists or P-Lists, but
that's probably more advanced than you want to get right now.

> what is "setf" and how to write it in terms of the elementary
> functions, car/cdr/cons/quote/cond/atom/eq ?

SETF is a macro, not a function, and a particularly complicated one.
You should read up on macros in general before trying to understand how
SETF is implemented.

> how to conveniently costruct the list that goes with getf ?

You can't construct anything with GETF. GETF is an accessor.

rg

Mark Wooding

unread,
Dec 5, 2010, 3:56:57 PM12/5/10
to
Katalin Sinkov <lisps...@gmail.com> writes:

> On Dec 4, 4:05 pm, Don Geddis <d...@geddis.org> wrote:
> > You just don't know lisp.
>
> Do you know lisp ?

He seems to.

> Do you even know how to fork off another thread if that is your issue
> with the heading ?

Usually one forks processes.

> Also, style cannot be decoupled from skill of language. Even if you
> learnt all the C, you could not write a C++ style virtual class in it
> unless you had the skill.

There's no such thing. Are you referring to a class with virtual
members, or a class with a virtual base class? The former is pretty
trivial; the latter is somewhat interesting. But none of this is to do
with style.

> The most you would be able to achieve would be methods with function
> pointers.

Starting from C will do that, yes.

> > Oh, and by the way: the functions your listed are not "the elementary
> > functions" (lisp has lots of functions, and there is no unique
> > elementary subset); nor can SETF be written in terms of the ones you
> > listed.
>
> But you have one set provided to you on silver plate to use. Must I
> provide you with all of them before you will activate your neuron and
> lift your finger to explain how setf is implemented ?

SETF is a macro. It examines its place argument, decodes it (possibly
by macroexpanding it), and attempts to find a SETF-expansion for it (see
GET-SETF-EXPANSION). It expands to a relatively simple function of this
SETF-expansion, if it exists (binding relevant subexpressions of the
place and the new value to temporaries using LET* and invoking the
setter form); if it doesn't exist then SETF signals an error.

Are you any the wiser?

-- [mdw]

Pascal J. Bourguignon

unread,
Dec 5, 2010, 5:31:01 PM12/5/10
to
RG <rNOS...@flownet.com> writes:

This is not correct. GETF is special:

CL-USER> (let ((plist '()))
(setf (getf plist :k1) 1
(getf plist :k2) 2)
plist)
(:K2 2 :K1 1)

Setfers are able to do such things.

Don Geddis

unread,
Dec 5, 2010, 6:17:39 PM12/5/10
to
For anyone lurking: Katalin sent this post to me also by email, so I
replied by email, not realizing that it was also posted to the
newsgroups.

I won't bother the newsgroups by posting my email reply.

-- Don
_______________________________________________________________________________

RG

unread,
Dec 6, 2010, 12:45:59 AM12/6/10
to
In article <87aakjk...@kuiper.lan.informatimago.com>,

"Pascal J. Bourguignon" <p...@informatimago.com> wrote:

> RG <rNOS...@flownet.com> writes:
>
> > In article
> > <6e2fe51c-ff4c-429f...@n2g2000pre.googlegroups.com>,
> > Katalin Sinkov <lisps...@gmail.com> wrote:
> >
> >> how to conveniently costruct the list that goes with getf ?
> >
> > You can't construct anything with GETF. GETF is an accessor.
>
> This is not correct. GETF is special:
>
> CL-USER> (let ((plist '()))
> (setf (getf plist :k1) 1
> (getf plist :k2) 2)
> plist)
> (:K2 2 :K1 1)
>
> Setfers are able to do such things.

GETF is not unique in this regard. GETHASH works the same way. But
relying on GETF's ability to allocate storage for new keys is fraught
with peril, e.g.:

(defun make-new-plist () (list :key1 :value1))

(defun set-key (plist key value)
(setf (getf plist key) value))

(defun foo ()
(let* ((plist (make-new-plist)))
(set-key plist :key1 :new-value-1)
(set-key plist :key2 :value2)
plist))

(foo) ==> (:KEY1 :NEW-VALUE-1) ; What happened to key2?

I think it's better to advise beginners to avoid such things rather than
try to explain the sometimes subtle distinction between places and
first-class mutable data objects.

rg

Thomas A. Russ

unread,
Dec 6, 2010, 5:24:58 PM12/6/10
to
RG <rNOS...@flownet.com> writes:

> There's another solution that doesn't seem to have been mentioned yet:
>
> ? (defstruct thing width height weight)
> THING
> ? (setf thing (make-thing :width 1 :height 2 :weight 3))
> #S(THING :WIDTH 1 :HEIGHT 2 :WEIGHT 3)
> ? (thing-height thing)
> 2
> ? (slot-value thing 'height)
> 2

SLOT-VALUE is not guaranteed to work on structures. Whether it does or
not is implementation dependent. It hinges on the particular way
structures are implemented in each implementation, since they are not
required to belong to STANDARD-CLASS.

From the Hyperspec:

The specific behavior depends on object's metaclass. An error is
never signaled if object has metaclass standard-class. An error is
always signaled if object has metaclass built-in-class. The
consequences are unspecified if object has any other metaclass--an
error might or might not be signaled in this situation. Note in
particular that the behavior for conditions and structures is not
specified.

which explicitly notes that the behavior for structures is not
specified.

--
Thomas A. Russ, USC/Information Sciences Institute

0 new messages