Google Groups Home
Help | Sign in
Beginner question
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  11 messages - Collapse all
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
Yoel Jacobsen  
View profile
 More options Jan 31 2005, 4:19 am
Newsgroups: comp.lang.lisp
From: Yoel Jacobsen <y...@emet.co.il>
Date: Mon, 31 Jan 2005 11:19:43 +0200
Local: Mon, Jan 31 2005 4:19 am
Subject: Beginner question
I'm experimenting CL by attempting to write some basic programs.

I'm trying to write an /etc/passwd to LDIF converter and I'm stuck - I
can't figure out from CLISP errors what is wrong. Here is my code:

(require 'split-sequence)

(defmacro list-to-plist (plist pos-list id-list field-list)
   `(progn ,@(map 'list
        #'(lambda (id pos)
            `(setf (getf ,id ,id-list) (elt ,field-list ,pos)))
        plist pos-list)))

(defun pline-to-plist (line)
   "convert a passwd line to a plist"
   (let ((fields (split-sequence:split-sequence #\: line))
                 (entry nil))
     (list-to-plist
      '(:login :passwd :uid :gid :group :home :shell)
      '(0 1 2 3 4 5 6 7)
      entry fields)
     entry))

(format t "~S~%" (pline-to-plist
"news:x:9:13:news:/usr/lib/news:/bin/false"))

I tried to use a macro to shorten the following pattern:
(SETF (GETF :LOGIN ENTRY) (ELT FIELDS 0))
(SETF (GETF :PASSWD ENTRY) (ELT FIELDS 1))
(SETF (GETF :UID ENTRY) (ELT FIELDS 2))
(SETF (GETF :GID ENTRY) (ELT FIELDS 3))
(SETF (GETF :GROUP ENTRY) (ELT FIELDS 4))
(SETF (GETF :HOME ENTRY) (ELT FIELDS 5))
(SETF (GETF :SHELL ENTRY) (ELT FIELDS 6))

Now, I get diffetent errors:
Inside SLIME -
        FUNCALL: undefined function NIL
           [Condition of type SYSTEM::SIMPLE-UNDEFINED-FUNCTION]
When evaluating directly with CLISP:
        *** - SYSTEM::%EXPAND-FORM: invalid form (0 1 2 3 4 5 6 7)

Where did I wrong?


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
drewc  
View profile
 More options Jan 31 2005, 5:34 am
Newsgroups: comp.lang.lisp
From: drewc <dr...@rift.com>
Date: Mon, 31 Jan 2005 10:34:26 GMT
Local: Mon, Jan 31 2005 5:34 am
Subject: Re: Beginner question

Yoel Jacobsen wrote:
> I'm experimenting CL by attempting to write some basic programs.

> I'm trying to write an /etc/passwd to LDIF converter and I'm stuck - I
> can't figure out from CLISP errors what is wrong. Here is my code:

the short answer : read "Practical Common Lisp" by Peter Seibel.

The entire book is available online at:

http://gigamonkeys.com/book/

By the time you finish you will have a better grasp on how we use lisp
to perform simple tasks like your converter.

the shorter answer :

(defun pline->plist (pline)
           (loop
            for name in '(:login :passwd :uid :gid :group :home :shell)
            for value in (split-sequence:split-sequence #\: pline)
              append (list name value)))

The critical answer:

You don't need any new macros, and you almost certainly do not want to
use plists that way. You need to learn common lisp before you can use
it! Peter's book is a good start.

> Where did I wrong?

Where I start!

drewc


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Andreas Thiele  
View profile
 More options Jan 31 2005, 5:42 am
Newsgroups: comp.lang.lisp
From: "Andreas Thiele" <nospam6...@nospam.com>
Date: Mon, 31 Jan 2005 11:42:34 +0100
Local: Mon, Jan 31 2005 5:42 am
Subject: Re: Beginner question
"Yoel Jacobsen" <y...@emet.co.il> schrieb im Newsbeitrag
news:ctkt7f$ipm$1@news2.netvision.net.il...

Yoel,

you should use (macroexpand '(list-to-plist ...)) to see what your macro
really creates.

Let me suggest a typical lisp idiom to solve your problem:

(defun pline-to-plist (x)
  (mapcan #'(lambda (key value) (list key value))
          '(:login :passwd :uid :gid :group :home :shell)
          (split-sequence:split-sequence #\: x)))

Another more verbose iterative solution might be easier to read:

(defun pline-to-plist2 (x)
  (let ((r '()))
    (mapc #'(lambda (key value)
              (push key r)
              (push value r))
          '(:login :passwd :uid :gid :group :home :shell)
          (split-sequence:split-sequence #\: x))
    (nreverse r)))

Andreas


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Kenny Tilton  
View profile
 More options Jan 31 2005, 6:33 am
Newsgroups: comp.lang.lisp
From: Kenny Tilton <ktil...@nyc.rr.com>
Date: Mon, 31 Jan 2005 11:33:28 GMT
Local: Mon, Jan 31 2005 6:33 am
Subject: Re: Beginner question

It is a little tricky:

(macroexpand-1 '(list-to-plist
      '(:login :passwd :uid :gid :group :home :shell)
      '(0 1 2 3 4 5 6 7)
      entry fields))
(PROGN (SETF (GETF QUOTE ENTRY) (ELT FIELDS QUOTE))
        (SETF (GETF (:LOGIN :PASSWD :UID :GID :GROUP :HOME :SHELL)
ENTRY) (ELT FIELDS (0 1 2 3 4 5 6 7))))

Note that my first bit of help here is that you can debug macros by
seeing what they will expand into. My second tip is that you can use
print statements in a macro to see what is going on during the macro
expansion, ie, when the function containing the macro usage gets
compiled, or when you simply macroexpand a usage.

That might still not help, because you will just see '(:login...) as the
plist parameter if you just say (print plist). The problem is that you
will not notice that the quote should not be there. When you
interactively (print '(1 2 3)) the output will be just (1 2 3), not '(1
2 3).

Not knowing this, you might get frustrated and say instead:

    (dolist (p plist) (print p))

Then you would see:

QUOTE
(:LOGIN....)

...and the light might go on. Or maybe not, because macros really are
tricky. They get passed the symbolic source, not dynamic runtime values.

Try macroexpanding this (note that the quotes are gone):

(macroexpand-1
  '(list-to-plist
      (:login :passwd :uid :gid :group :home :shell)
      (0 1 2 3 4 5 6 7)
      entry fields))

=>
(PROGN (SETF (GETF :LOGIN ENTRY) (ELT FIELDS 0)) (SETF (GETF :PASSWD
ENTRY) (ELT FIELDS 1))
        (SETF (GETF :UID ENTRY) (ELT FIELDS 2)) (SETF (GETF :GID ENTRY)
(ELT FIELDS 3))
        (SETF (GETF :GROUP ENTRY) (ELT FIELDS 4)) (SETF (GETF :HOME
ENTRY) (ELT FIELDS 5))
        (SETF (GETF :SHELL ENTRY) (ELT FIELDS 6)))

That is the code you want. I think the next thing you will be debugging
is (getf :login entry), where I think you wanted (getf entry :login),
but that is another story.

kt

--
Cells? Cello? Cells-Gtk?: http://www.common-lisp.net/project/cells/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film

"Doctor, I wrestled with reality for forty years, and I am happy to
state that I finally won out over it." -- Elwood P. Dowd


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Yoel Jacobsen  
View profile
 More options Jan 31 2005, 7:28 am
Newsgroups: comp.lang.lisp
From: Yoel Jacobsen <y...@emet.co.il>
Date: Mon, 31 Jan 2005 14:28:42 +0200
Local: Mon, Jan 31 2005 7:28 am
Subject: Re: Beginner question
Andreas,

Thanks! Yet, I still would like to know what went wrong so I wouldn't
repeat it in the future.

I did the macroexpand-1 test and it looked just fine -

CL-USER> (macroexpand-1 '(list-to-plist
      (:login :passwd :uid :gid :group :home :shell)
      (0 1 2 3 4 5 6 7)
      entry fields) )
(PROGN (SETF (GETF :LOGIN ENTRY) (ELT FIELDS 0))
  (SETF (GETF :PASSWD ENTRY) (ELT FIELDS 1))
  (SETF (GETF :UID ENTRY) (ELT FIELDS 2))
  (SETF (GETF :GID ENTRY) (ELT FIELDS 3))
  (SETF (GETF :GROUP ENTRY) (ELT FIELDS 4))
  (SETF (GETF :HOME ENTRY) (ELT FIELDS 5))
  (SETF (GETF :SHELL ENTRY) (ELT FIELDS 6)))
T
CL-USER>

I removed the quote before both lists (the plist and the range).

Any Idea,

Thanks again

Yoel


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Andreas Thiele  
View profile
 More options Jan 31 2005, 9:48 am
Newsgroups: comp.lang.lisp
From: "Andreas Thiele" <nos...@nospam.com>
Date: Mon, 31 Jan 2005 15:48:45 +0100
Local: Mon, Jan 31 2005 9:48 am
Subject: Re: Beginner question

"Yoel Jacobsen" <y...@emet.co.il> schrieb im Newsbeitrag
news:ctl89r$mr5$1@news2.netvision.net.il...

> Andreas,

> Thanks! Yet, I still would like to know what went wrong so I wouldn't
> repeat it in the future.

Yoel,

you can define the following macro to see what is going on:

(defmacro test1 (x) `(identity ,x))

Now my lisp answers:

CL-USER 43 > (macroexpand '(test1 '(1 2)))
(IDENTITY (QUOTE (1 2)))
T

You might also write:

(defmacro test2 (x)
  `(format t "~s" ,(format nil "~s" x)))

to see what x contains within a comma expression:

CL-USER 46 : 1 > (test2 '(1 2))
"(QUOTE (1 2))"
NIL

Thus you have (at least) two possible solutions:

(defmacro list-to-plist (plist pos-list id-list field-list)
  `(progn ,@(map 'list
                 #'(lambda (id pos)
                     `(setf (getf ,id-list ,id) (elt ,field-list ,pos)))
                 `(,@(cadr plist))
                 `(,@(cadr pos-list))
                 )))

Notice: argument to getf changed. Your function pline-to-plist remains
unchanged.

Second possiblity:

(defmacro list-to-plist (plist pos-list id-list field-list)
  `(progn ,@(map 'list
                 #'(lambda (id pos)
                     `(setf (getf ,id-list ,id) (elt ,field-list ,pos)))
                 plist
                 pos-list)))

(defun pline-to-plist (line)
   "convert a passwd line to a plist"
   (let ((fields (split-sequence:split-sequence #\: line))
                 (entry nil))
     (list-to-plist
       (:login :passwd :uid :gid :group :home :shell)
       (0 1 2 3 4 5 6 7)
       entry fields)
     entry))

Notice: the quotes in pline-to-plist are gone.

I'd utterly agree to Kenny. Lisp is different! At least for me. For most
other languages I roughly browsed a nice book.  To explore its strength Lisp
needs studying literature. Here are some suggestions:

http://www.alu.org is a good starting point.
http://www.gigamonkeys.com/book is great compact and easy to read (my
opinion)
http://www.paulgraham.com/onlisp.html is a standard

Hope this helps a bit further.

Andreas


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
yoel.jacob...@gmail.com  
View profile
 More options Jan 31 2005, 1:13 pm
Newsgroups: comp.lang.lisp
From: yoel.jacob...@gmail.com
Date: 31 Jan 2005 10:13:51 -0800
Local: Mon, Jan 31 2005 1:13 pm
Subject: Re: Beginner question
Drew,

Thanks. I'm actually reading this book and do find it readable and
practical. Yet, I can't read such a book from cover to cover without
any practice. I find that  simple daily tasks to be a good practice.

I just wonder regarding your recommendation against plist for storing
my strucutre. Practical Lisp clearly recommends Hash Tables for large
tables and plists/alists for small tables for efficiency reasons.

May you please elaborate?

Yours,
Yoel


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Pascal Bourguignon  
View profile
 More options Jan 31 2005, 3:12 pm
Newsgroups: comp.lang.lisp
From: Pascal Bourguignon <s...@mouse-potato.com>
Date: 31 Jan 2005 21:12:47 +0100
Local: Mon, Jan 31 2005 3:12 pm
Subject: Re: Beginner question

yoel.jacob...@gmail.com writes:
> Drew,

> Thanks. I'm actually reading this book and do find it readable and
> practical. Yet, I can't read such a book from cover to cover without
> any practice. I find that  simple daily tasks to be a good practice.

> I just wonder regarding your recommendation against plist for storing
> my strucutre. Practical Lisp clearly recommends Hash Tables for large
> tables and plists/alists for small tables for efficiency reasons.

> May you please elaborate?

It's all in the constants.

Access time to sequential structures like p-lists or a-lists is O(N),
with N=number of entries, while for hash-table, it's anything between
O(1) and  O(log(N)), which is much better.  But really, it's only
better when N -> +infinity, because for hash-table you must spend a
lot of time computing the hash value for the key (with SXHASH), it's
usually slower than comparing a few keys in the lists, and "few" can
be as high as 50, depending on the test function (EQL hash is faster
than EQUALP hash).

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

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
drewc  
View profile
 More options Jan 31 2005, 5:51 pm
Newsgroups: comp.lang.lisp
From: drewc <dr...@rift.com>
Date: Mon, 31 Jan 2005 22:51:32 GMT
Local: Mon, Jan 31 2005 5:51 pm
Subject: Re: Beginner question

yoel.jacob...@gmail.com wrote:
> Drew,

> Thanks. I'm actually reading this book and do find it readable and
> practical. Yet, I can't read such a book from cover to cover without
> any practice. I find that  simple daily tasks to be a good practice.

Ah good! Practice makes perfect.

> I just wonder regarding your recommendation against plist for storing
> my strucutre. Practical Lisp clearly recommends Hash Tables for large
> tables and plists/alists for small tables for efficiency reasons.

Nothing with plists per-se, as my PLINE->PLIST function returns one. its
  the use of a symbols plist that is generally frowned apon.

A plist (property list) is simply a list of key/value pairs. An alist
(associative list) is a list of lists whose CAR is the key and CDR is
the value.

For some (mostly historical) reason, you can also access the plist of a
symbol. Each symbol carries a plist that can be accessed with
SYMBOL-PLIST. Using the property list of a symbol is almost never what
you want to do.. it's much easier to use a regular list, and leads to
less confusion.

;;;create a plist and assign it to FOOLIST
CL-USER> (defparameter foolist '(:foo "foo" :bar "bar" :baz "baz"))
FOOLIST
CL-USER> foolist
(:FOO "foo" :BAR "bar" :BAZ "baz")

Note that foolist is just a normal variable, and has no plist bound to it:

CL-USER> (symbol-value 'foolist)
(:FOO "foo" :BAR "bar" :BAZ "baz")
CL-USER> (symbol-plist 'foolist)
NIL

One accesses the value of the plist using getf, but the place is the
plist itself, not the symbol :

CL-USER> (getf foolist :bar)
"bar"
CL-USER> (setf (getf foolist :bar) "bat")
"bat"
CL-USER> (getf foolist :bar)
"bat"

You can also assign values to a symbols plist. This is what i was
recomending against as it can add to confusion really quickly (it's like
yet-another-namespace.. two is enough!).

the plist of a symbol can be accessed via SYMBOL-PLIST (just as the
value binding can be discovered via SYMBOL-VALUE and the function of a
symbol via SYMBOL-FUNCTION.)

(setf (symbol-plist 'foolist) foolist)
(:FOO "foo" :BAR "bat" :BAZ "baz")
CL-USER> (symbol-plist 'foolist)
(:FOO "foo" :BAR "bat" :BAZ "baz")

This is where it can get confusing. to access the values of the symbols
plist, on uses get (not getf, although getf may work in clisp) with a
SYMBOL as the PLACE :

CL-USER> (get 'foolist :bar)
"bat"
CL-USER> (setf (get 'foolist :bar) "bar")
"bar"
CL-USER> (get 'foolist :bar)
"bar"

You see why this can get confusing? observe the following,

CL-USER> (setf (getf foolist :bar) "TEST")
"TEST"
CL-USER> (get 'foolist :bar)
"TEST"
CL-USER> (setf (symbol-plist 'foolist) (copy-list foolist))
(:FOO "foo" :BAR "TEST" :BAZ "baz")

CL-USER> (setf (getf foolist :bar) "TESTING 1 2 3")
"TESTING 1 2 3"
CL-USER> (get 'foolist :bar)
"TEST"
CL-USER> (getf foolist :bar)
"TESTING 1 2 3"

The first example appeared to work because FOOLIST and (SYMBOL-PLIST
'foolist) share a list. But then i make sure thay they point to
different lists, and all of a sudden things get wierd.

In the general case, you don't need symbol-plist, which can lead to
confusions such as the above. just use a regular list with alternating
key/value pairs ( a plist).

Alists are also very handy, i tend to favour them over plists for all
but the most simple cases.

drewc


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Peter Seibel  
View profile
 More options Jan 31 2005, 5:58 pm
Newsgroups: comp.lang.lisp
From: Peter Seibel <pe...@javamonkey.com>
Date: Mon, 31 Jan 2005 22:58:13 GMT
Local: Mon, Jan 31 2005 5:58 pm
Subject: Re: Beginner question

Except when it is. I give an example of what I think is a rightous use
of symbol property lists in Chapter 24. YMMV of course.

-Peter

--
Peter Seibel                                      pe...@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp


    Reply to author    Forward