0
votes

I'm curious if there is a way to end a backquoted symbol list with a period following a comma inserted value.

Here is the sample code:

(defparameter *things* '(book pencil shoe))
(defun inspect-item (item things)
    (if (member item things)
        `(you pick up the ,item and yeet it out the window.)
        `(only realize the truth... there is no ,item.)))

This will succeed (print (inspect-item 'book *things*)) and it produces the symbol list (YOU PICK UP THE BOOK AND YEET IT OUT THE WINDOW.). I assume in this case that the period is part of the symbol WINDOW. (as confirmed using the last function).

However, this will fail (print (inspect-item 'spoon *things*)) claiming that variable ITEM. has no value (Because it thinks the name is item.). Leaving a space between item and the period gives the error illegal end of dotted list which I assume is because it is assuming I'm using dotted list syntax.

Is there any way to get it to produce the symbol I want at the end (BOOK.)?

3

3 Answers

4
votes

Possible requirements for a solution

You need to create a new symbol based on an old one:

  • the same name, with a . appended
  • probably in the same package

Period as a symbol

Note that you can write a symbol with the period as a name using an escaped symbol: |.| or \..

CL-USER 17 > (let ((item 'foobar))
               `(only realize the truth... there is no ,item \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.)

princ prints without escape characters:

CL-USER 18 > (princ '(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.))
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR .)       ; <- printed output
(ONLY REALIZE THE TRUTH... THERE IS NO FOOBAR \.)      ; <- REPL value

Solution

CL-USER 19 > (defun add-suffix (symbol suffix)
               (intern (concatenate 'string
                                    (symbol-name symbol)
                                    (symbol-name suffix))
                       (symbol-package symbol)))
ADD-SUFFIX

CL-USER 20 > (let ((item 'tree))
               `(we went to the ,(add-suffix item '|.|)))
(WE WENT TO THE TREE.)

It can also be useful to use the flexibility of format instead of using concatenate.

CL-USER 22 > (defun add-suffix (symbol suffix)
               (intern (format nil "~a~a" symbol suffix)
                       (symbol-package symbol)))
ADD-SUFFIX
3
votes

I think that the real problem lies in the attempt to produce text just as the printed representation of a list of symbols. Those are completely different things. The only reason to do it like this could be as some kind of exercise. There are a number of introductory texts that do that kind of thing.

Instead, I'd advise to actually produce text, i. e. strings. You might use the format function that is quite flexible for inserting variable things:

(defparameter *things* '("book" "pencil" "shoe"))

(defun inspect-item (item things)
  (if (member item things :test #'string-equal)
      (format nil
              "You pick up the ~a and yeet it out the window."
              item)
      (format nil
              "Only realize the truth… there is no ~a."
              item)))
1
votes

I partly agree with Svante that turning lists of symbols into text is often the wrong thing. On the other hand things like parsers &c often want to think in terms of symbols rather than strings as symbols have nice properties like (eq a b) working the way you would hope.

That being said, here's an alternative approach: create a list of words and then have a function which turns them into a string representing a sentence, adding appropriate punctuation and capitalization.

(defparameter *things* '(book pencil shoe))

(defun inspect-item (item things)
  (sentencify (if (member item things)
                  `(you pick up the ,item and yeet it out the window)
                `(only realize the truth... there is no ,item))))

(defun sentencify (slist &key (question nil))
  (format nil "~{~A~^ ~}~A"
          (loop for first = t then nil
                for w in slist
                for ws = (typecase w
                           (symbol (symbol-name w))
                           (string w)
                           (t w))
                collect (typecase ws
                          (string (if first
                                      (string-capitalize ws)
                                    (string-downcase ws)))
                          (t ws)))
          (if question "?" ".")))

And now:

> (inspect-item 'book *things*)
"You pick up the book and yeet it out the window."

> (inspect-item 'bok *things*)
"Only realize the truth... there is no bok."

> (inspect-item '(x . y) *things*)
"Only realize the truth... there is no (x . y).