質問

I've been working on a small project in Lisp recently to practice. It's a simple database creator/manager, and so far, it works pretty well! I only have one problem: When I dump the property list that is the database in [what should be] a human readable format, I can only print the values. I also need to print the property name and, with my current function, I can't.

Here's my code so far (Writing from memory, it isn't copy/pasted):

(defun dump-list (list-to-dump &optional prefix)
  (if (not (boundp prefix)) (setq prefix "") ;If it's nil, bind it to ""
  (if (not (stringp prefix)) ;If they specified anything other than a string
    (format "~a~%" "argument:prefix must be a string!")) ;then yell at them.
  (dolist (item list-to-dump) ;Iterate through the items in the list
    (if (listp item) ;If the item itself is a list (nested lists)
      (dump-list item (concatenate 'string prefix "  "));then dump that too, indented
    (format t "~a~%" item)));Here's where I need help. I can't figure out how to
                        ;output the value and its label at the same time.

It works pretty well, but only prints the value stored, not the name of the property. I am looking for something formatted like this:

LABEL1: VALUE1
LABEL2: VALUE2
LABEL3:
  NESTEDLABEL1: NESTEDVAL1
  NESTEDLABEL2: NESTEDVAL2
  NESTEDLABEL3: 
    TOOMANYLAYERS:YEP.
    SORRY: ABOUT THAT.

for a list created like this:

(list :LABEL1 "VALUE1" :LABEL2 "VALUE2" :LABEL3
  (list :NESTEDLABEL1 "NESTEDVALUE1" :NESTEDLABEL2 "NESTEDVALUE2" :NESTEDVALUE3
    (list :TOOMANYLAYERS "YEP." :SORRY "ABOUT THAT.")))

Sorry for any incorrect syntax there, I'm by no means an expert in Lisp.

prefix is so that, if you want indenting, it can happen. It's mostly used to print the child lists two more spaces than their parent list.

I'll do my best to stay up to date, but I am in school so probably can't check this until around six hours from now, which is when I get home.

役に立ちましたか?

解決

  1. You forgot to pass the first argument (result-type) to concatenate.

  2. You forgot to pass the first argument (destination) to format.

  3. Your default argument handling can be simplified.

  4. Please avoid dangling parens, they violate the accepted style.

  5. To answer your actual question: use loop

Here is my code:

(defun dump-list (list-to-dump &optional (prefix ""))
  (unless (stringp prefix) ; or (check-type prefix string) instead of the whole unless form
    (setq prefix (princ-to-string prefix))) ; or (coerce prefix 'string) instead of princ
  (fresh-line) ; start with a new line if something has already been printed
  (loop :for (label item) :on list-to-dump :by #'cddr :do
    (format t "~a~a:" prefix label)
    (if (consp item) ; treat NIL as a single value, not a list
        (dump-list item (concatenate 'string prefix "  "))
        (format t " ~a~%" item))))

It prints what you want:

LABEL1: VALUE1
LABEL2: VALUE2
LABEL3:
  NESTEDLABEL1: NESTEDVALUE1
  NESTEDLABEL2: NESTEDVALUE2
  NESTEDVALUE3:
    TOOMANYLAYERS: YEP.
    SORRY: ABOUT THAT.

If you insist on checking the type of prefix (instead of converting it to a string), please use check-type as indicated in the code.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top