Print a raw pathname structure - common-lisp

Using CCL, when I print a pathname using, e.g., (format t "~s" pathname), or with pprint, or with print, it prints out with the #P reader syntax. For instance:
? (make-pathname :directory "foo")
#P"foo/"
? (format t "~s" (make-pathname :directory "foo"))
#P"foo/"
NIL
I'd really like to see the underlying pathname structure, so that I can tell exactly what the object looks like. Is there a way to print it raw?

I don't know if that's what you're looking for, but you could call the inspector
(inspect thing)
CCL example:
? (inspect (make-pathname :directory "foo"))
[0] #P"foo/"
[1] Type: PATHNAME
[2] Class: #<BUILT-IN-CLASS PATHNAME>
[3] TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x14083886>)
[4] %PATHNAME-DIRECTORY: (:RELATIVE "foo")
[5] %PATHNAME-NAME: NIL
[6] %PATHNAME-TYPE: NIL
[7] %PHYSICAL-PATHNAME-VERSION: NIL
[8] %PHYSICAL-PATHNAME-DEVICE: NIL
Inspect> help
The following toplevel commands are available:
<n> the same as (:I <n>)
(:S N V) set the <n>th line of object data to value <v>
:HOME show first page of object data
:PREV show previous page of object data
:NEXT show next page of object data
:SHOW re-show currently inspected object (the value of CCL:#)
:Q exit inspector
:POP exit current inspector level
(:I N) inspect <n>th item
:? help
:PWD Print the pathame of the current directory
(:CD DIR) Change to directory DIR (e.g., #p"ccl:" or "/some/dir")
(:PROC &OPTIONAL P) Show information about specified process <p>/all processes
(:KILL P) Kill process whose name or ID matches <p>
(:Y &OPTIONAL P) Yield control of terminal-input to process
whose name or ID matches <p>, or to any process if <p> is null
Any other form is evaluated and its results are printed out.
Inspect>
Example on ideone with CLISP

In addition to inspect, you can use describe:
? (describe #P"/tmp/**/file.*")
#P"/tmp/**/file.*"
Type: PATHNAME
Class: #<BUILT-IN-CLASS PATHNAME>
TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x30004003ED0D>)
%PATHNAME-DIRECTORY: (:ABSOLUTE "tmp" :WILD-INFERIORS)
%PATHNAME-NAME: "file"
%PATHNAME-TYPE: :WILD
%PHYSICAL-PATHNAME-VERSION: :NEWEST
%PHYSICAL-PATHNAME-DEVICE: NIL

This is a problem with format directives, change "S" with "A" that prints the string, "S" (try to) prints a valid object that can read the REPL or the function read
; SLIME 2016-04-19
CL-USER> (format t "~s" (make-pathname :directory "foo"))
#P"/foo/"
NIL
CL-USER> (format t "~A" (make-pathname :directory "foo"))
/foo/
NIL
from the tutorial a few format receipes
"~S" tries to generate output that can be read back in with READ.
Thus, strings will be enclosed in quotation marks, symbols will be
package-qualified when necessary, and so on. Objects that don't have a
READable representation are printed with the unreadable object syntax
"<>." With a colon modifier, both the ~A and ~S directives emit NIL as
() rather than NIL. Both the ~A and ~S directives also take up to
four prefix parameters, which can be used to control whether padding is > added after (or before with the at-sign modifier) the value, but those
parameters are only really useful for generating tabular data.
finally only to get the string put nil instead of t wich redirect to standard output
CL-USER> (format nil "~A" (make-pathname :directory "foo"))
"/foo/"

Related

Why when I create an class can't find-symbol it?

I'm confuse about the symbols now, I tried:
CL-USER> (defclass foo2 () ())
#<STANDARD-CLASS COMMON-LISP-USER::FOO2>
CL-USER> (describe 'foo2)
COMMON-LISP-USER::FOO2
[symbol]
FOO2 names the standard-class #<STANDARD-CLASS COMMON-LISP-USER::FOO2>:
Direct superclasses: STANDARD-OBJECT
No subclasses.
Not yet finalized.
No direct slots.
; No value
CL-USER> (find-symbol "foo2")
NIL
NIL
Why I can't found the "foo2" symbol with the find-symbol function?
What I want do with this:
CL-USER> (defun my-make-instance (name n) (make-instance (make-symbol (format nil "~a-~a" name n)))
MY-MAKE-INSTANCE
CL-USER> (my-make-instance "foo" 2)
; Evaluation aborted on #<SB-PCL:CLASS-NOT-FOUND-ERROR foo2 {1003A3A003}>.
And I get:
There is no class named #:|foo2|.
how to I do this?
And other case:
CL-USER> (describe 'foo2)
COMMON-LISP-USER::FOO2
[symbol]
FOO2 names the standard-class #<STANDARD-CLASS COMMON-LISP-USER::FOO2>:
Direct superclasses: STANDARD-OBJECT
No subclasses.
Not yet finalized.
No direct slots.
; No value
CL-USER> (describe (intern "foo2"))
COMMON-LISP-USER::|foo2|
[symbol]
; No value
Why it happened? Is the "foo2" create by defclass a internal symbol, isn't?
Common Lisp is case sensitive and the reader is case converting; your source code generally gets converted to upper case when it is read by the compiler / interpreter. The symbol named "foo2" does not exist in your example, but the symbol named "FOO2" does.
The call to make-symbol will return a new symbol object, not the symbol object associated with your class.
The easiest way to fix your code would be to replace your make-symbol call in my-make-instance with a call to read-from-string to get the same case converting reader behavior to be used on your argument string. The reader will then also intern the symbol in the current package, ensuring it is the same symbol object as the one associated with your class. You also probably want to use defun instead of defmacro to define my-make-instance in this case.
In short you probably want the following code:
(defun my-make-instance (name n)
(make-instance (read-from-string (format nil "~a-~a" name n))))
(defclass foo-2 () ())
(my-make-instance "foo" 2)
;returns below instance
#<FOO-2 {100AB67443}>
If you describe the symbol and get
FOO2 names the standard-class #<STANDARD-CLASS COMMON-LISP-USER::FOO2>:
then FOO2 in uppercase characters really indicates that the symbol has an uppercase name.
* 'foo2
FOO2
Now you can use the function symbol-name to get the name of a symbol as a string:
* (symbol-name 'foo2)
"FOO2"
As you can see above, the name is uppercase.
Using the uppercase name to find the symbol then works:
* (find-symbol "FOO2")
FOO2
:INTERNAL

Backquote symbol list ending in period

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.)?
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
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)))
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).

Remove one method from a generic function

I have added the following method to the generic function speak but would now like to remove this particular method in the REPL without removing the rest of the generic functions' methods.
(defmethod speak :around ((c courtier) string) ; [1]
(format t "Does the King believe that ~A?" string)
(if (eql (read) 'yes)
(if (next-method-p) (call-next-method)) ; [2]
(format t "Indeed, it is a preposterous idea.~%"))
'bow)
[1] The :around method replaces the primary method for the type.
[2] Then it decides whether to call the primary method or not.
The documentation link to the function remove-method has no examples and I don't know what is the syntax to refer to the actual :around method above.
(remove-method #'speak)
TOO FEW ARGUMENTS
(remove-method #'speak :around)
NO-APPLICABLE-METHOD
From the documentation:
remove-method generic-function method
It expects a generic function object and a method object as arguments.
One can find the method via find-method.
CL-USER 39 > (find-method #'speak
(list :around)
(list (find-class 'courtier) (find-class t)))
#<STANDARD-METHOD SPEAK (:AROUND) (COURTIER T) 42001285EB>
CL-USER 40 > (remove-method #'speak
(find-method #'speak
(list :around)
(list (find-class 'courtier)
(find-class t))))
#<STANDARD-GENERIC-FUNCTION SPEAK 422000A68C>
Note also that a good Lisp development environment may also allow to remove methods in the editor or the inspector.
Note that in the Lisp listener, one does not need to call find-method twice like above. The variable * contains the last result.
CL-USER 43 > (find-method #'speak
(list :around)
(list (find-class 'courtier)
(find-class t)))
#<STANDARD-METHOD SPEAK (:AROUND) (COURTIER T) 4200150DEB>
CL-USER 44 > (remove-method #'speak *)
#<STANDARD-GENERIC-FUNCTION SPEAK 422000A68C>
Here is another interaction example using SLIME in GNU Emacs with the presentation feature for SLIME enabled. A presentation is Lisp output, which keeps the connection between the printed object and the generated text.
Call the find-method function. It returns the method. Here we use presentations, which keep the connections between text and Lisp objects. The output is displayed in the color red and it is mouse-sensitive. Moving the mouse over the red returned object will add interaction options.
Now type (remove-method #'speak and then middle-click (or whatever SLIME is configured to use) on the red output: the presentation (the text and the connected object) will be copied to the line. Type ) and enter the form. SLIME has actually constructed a list with the real object and not the textual representation, then.
This is how repls work on the Symbolics Lisp Machine and in CLIM / McCLIM...
If using GNU Emacs with SLIME, you can also use slime-inspector. For example define generic function foo and two methods:
USER> (defgeneric foo (x))
#<STANDARD-GENERIC-FUNCTION FOO (0)>
USER> (defmethod foo ((x string)) (length x))
#<STANDARD-METHOD FOO (STRING) {100B4D7E23}>
USER> (defmethod foo ((x integer)) x)
#<STANDARD-METHOD FOO (INTEGER) {100C355843}>
You have two main options to enter the inspector:
From the REPL, type #'foo so that a presentation object for the generic method is printed:
USER> #'foo
#<STANDARD-GENERIC-FUNCTION FOO (0)>
Either right-click the presentation (anywhere inside #<...>) and select Inspect, or put the cursor in the presentation and press C-c C-v TAB (slime-inspect-presentation-at-point).
From a source file, enter slime-inspect, a.k.a. C-c I, and enter #'foo.
In both cases, you are shown a view similar to this:
#<STANDARD-GENERIC-FUNCTION {505A9A2B}>
--------------------
Name: FOO
Arguments: (X)
Method class: #<STANDARD-CLASS COMMON-LISP:STANDARD-METHOD>
Method combination: #<SB-PCL::STANDARD-METHOD-COMBINATION STANDARD () {1000214003}>
Methods:
(INTEGER) [remove method]
(STRING) [remove method]
(....)
Each [remove method] text is actually a button, click or press Return on any of them to remove the associated method from the generic function.

How to pass s-exp to parameter of non s-exp type in Common Lisp?

Question: How to force a s-exp to be evaluated before passing to a function expecting parameter of string type or else.?
This code is fine (no error):
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(("123" "456"))))
However, when passing a s-exp such as (first line) instead of "123":
(setf line '("123" "456"))
(setf (slot-value (ole sheet :range "A1:B1") 'value)
`(((first line) (second line)))))
There is error message:
The value FIRST is not of the expected type (OR
STRING
FIXNUM
SINGLE-FLOAT
DOUBLE-FLOAT).
[Condition of type TYPE-ERROR]
Restarts:
0: [RETRY] Retry SLIME REPL evaluation request.
1: [*ABORT] Return to SLIME's top level.
2: [ABORT-BREAK] Reset this thread
3: [ABORT] Kill this thread
I know what the problem is. But is there way get rid of this restriction? Because we would need to put the line of code inside a loop, so can't fix the parameter value to such as "123"...
I try using macro:
(defmacro set-line (par1 par2)
`(setf (slot-value (ole sheet :range "A1:B1") 'value)
`((,par1 ,par2))))
However, it doesn't work. Still the same error message saying the wrong type (first line)...
(set-line (first line) (second line))
Also I don't know how to escape the backquote ` if it appears inside macro body. I have tried put a \ in front of backquote inside the macro body, but then the \ would also appear upon macro expand.
`(setf xxx ` <--- another backquote
`(setf xxx \` <--- this can't escape backquote inside macro body
Thanks.
Background: when playing with Win32 OLE Excel example in:
https://github.com/quek/cl-win32ole/blob/master/example/excel.lisp
You are missing the basics of quotation. Your expression
? `(("123" "456")) ; quasiquote
(("123" "456"))
is a list containing a list and can also be created using the function LIST as
? (list (list "123" "456")) ; list
(("123" "456"))
To use expressions, you can either use unquote (note the preceding comma)
? `((,(first line) ,(second line))) ; quasiquote with unquote
(("123" "456"))
or, better
? `(,line)
(("123" "456"))
or use list :
? (list line)
(("123" "456"))

How to generate a string out of an (error)object without actual printing?

I want to retrieve the string, generated by write for further processing without doing any actual output, but write seems always to also output into the REPL
CL-USER>(let ((err-string (write (make-instance 'error) :stream nil)))
(do-awesome-stuff-with-string err-string))
<ERROR> ;;this is the printing I want to get rid of
"awesome-result"
Why does write still outputs into the REPL, and how do I get rid of that?
You can use with-output-to-string for this. Here's an example:
(flet ((do-awesome-stuff-with-string (string)
(concatenate 'string string " is awesome!")))
(let ((err-string (with-output-to-string (s)
(write (make-instance 'error) :stream s))))
(do-awesome-stuff-with-string err-string)))
;; => "#<ERROR {25813951}> is awesome!"
Here's here's the HyperSpec entry on with-output-to-string.
The reason (write (make-instance 'error) :stream nil) doesn't work is that the :stream argument to write is a stream designator and in that context nil is shorthand for *standard-output*. (The fact that format instead takes nil to mean that it should return a string is a common point of confusion).
Keep in mind that portably errors are made with MAKE-CONDITION. The standard does not say that errors are CLOS classes, so MAKE-INSTANCE might not work in some implementations.
There are two simple ways to get a string:
a) a textual description:
CL-USER 15 > (princ-to-string (make-condition 'error))
"The condition #<ERROR 4020311270> occurred"
b) the error object printed:
CL-USER 16 > (prin1-to-string (make-condition 'error))
"#<ERROR 402031158B>"

Resources