(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)
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.
> (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?
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:
> (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)
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):
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.
>>(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?
> 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 (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:
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.
> 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.
> 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).
> 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:
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.)
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 :
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.
>>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
drewc <dr...@rift.com> writes: > 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.
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.