Pretty-print newlines but not extra newlines - common-lisp

Is there a way, using the pretty printing machinery, to say, there needs to be a newline here, but not more than one?
I have added an S-expression node type for comments, and I am trying to make the pretty printer output them successfully. This is an example input in the preferred format
(defun f ()
; a
; b
z)
This is one attempt at pretty printing
(set-pprint-dispatch `(cons (eql ,+comment+)) #'print-comment)
and then
(defun print-comment (*standard-output* a)
(princ (cadr a)))
Produces this incorrect output
(DEFUN F () ; a ; b Z)
So the pretty printer doesn't know comments need to go on separate lines, fair enough, I need to tell it that
(defun print-comment (*standard-output* a)
(pprint-newline :mandatory)
(princ (cadr a))
(pprint-newline :mandatory))
And get this output
(DEFUN F ()
; a
; b
Z)
Which is no good either. Is there a way to tell the pretty printer to output a newline without the extra newlines?

Related

Define a constant array of struct known at compilation-time

In my program I have constant strings, the values are known at compilation time. For each offset there are currently 2 associated strings. I first wrote the following code:
(eval-when (:compile-toplevel :load-toplevel :execute) ;; BLOCK-1
(defstruct test-struct
str-1
str-2))
(eval-when (:compile-toplevel) ;; BLOCK-2
(defparameter +GLOBAL-VECTOR-CONSTANT+ nil) ;; ITEM-1
(let ((vector (make-array 10
:initial-element (make-test-struct)
:element-type 'test-struct)))
(setf (test-struct-str-1 (aref vector 0)) "test-0-1")
(setf (test-struct-str-2 (aref vector 0)) "test-0-2")
(setf +GLOBAL-VECTOR-CONSTANT+ vector)))
(format t "[~A]~%" (test-struct-str-1 (elt +GLOBAL-VECTOR-CONSTANT+ 0)))
(format t "[~A]~%" (test-struct-str-2 (elt +GLOBAL-VECTOR-CONSTANT+ 0)))
This seems to work as it returns the following:
[test-2-1]
[test-2-2]
In BLOCK-1 the struct containing the data is defined, for compile-time, load-time and execute-time. In BLOCK-2, the code which create a vector and sets the values is executed, at compile-time.
But I have the following concerns:
This code seems unnecessary verbose
The strings are stored in a structure
I need to manually set the offset of each values ((aref vector 0), (aref vector 1), etc).
When I set ITEM-1 inside BLOCK-1 instead of BLOCK-2 I get an error in SBCL which I don't understand
What is the idiomatic way to define complex constants in Common Lisp?
It's not really clear what you want to do from your question.
First important note: your code is seriously broken. It's broken because you define +global-vector-constant+ only at compile time but refer to it later than that. If you compile this file and then load that compiled file into a cold image you will get errors.
It is absolutely critical when dealing with things like this to make sure that your code will compile in a cold Lisp. One of the classic problems with resident environments (which CL isn't really, compared to the way Interlisp-D was for instance) is to end up with systems which you can't cold build: I'm pretty sure I worked for several years with an Interlisp-D sysout that no-one knew how to cold build any more.
If what you want is an object (an array, for instance) whose initial value is computed at compile time and then treated as a literal, then the answer to that is, in general, a macro: macros are exactly functions which do their work at compile time, and so a macro can expand to a literal. In addition it must be the case that the object you want to be a literal is externalizable (which means 'can be dumped in compiled files') and anything involved in it is known about at compile time. Instances of some classes are externalizable by default, those of some other classes can be made externalizable by user code, and some are not externalizable at all (for instance functions).
In quite a lot of simple cases, like the one you gave, if I understand it, you don't really need a macro, and in fact you can almost always get away without one, although it may make your code easier to understand if you do use one.
Here is a simple case: many arrays are externalizable if their elements are
(defparameter *my-strings*
#(("0-l" . "0-r")
("1-l" . "1-r")))
This means that *my-strings* will be bound to a literal array of conses of strings.
A more interesting case is when the elements are, for instance structures. Well, structures are also externalizable, so we can do that. And in fact it's quite possible, still, to avoid a macro, although it now becomes a bit noisy.
(eval-when (:compile-toplevel :load-toplevel :execute)
(defstruct foo
l
r))
(defparameter *my-strings*
#(#s(foo :l "0-l" :r "0-r")
#s(foo :l "1-l" :r "1-r")))
Note that the following won't work:
(defstruct foo
l
r)
(defparameter *my-strings*
#(#s(foo :l "0-l" :r "0-r")
#s(foo :l "1-l" :r "1-r")))
It won't work because, at compile time, you are trying to externalize instances of a structure which is not yet defined (but it probably will work if the Lisp is not cold, and you might even be able to reload the compiled file you made that way). Again, in this case you can avoid the eval-when in a larger system by ensuring that the file which defines the foo structure is compiled and loaded before the file with the defparameter is loaded.
And even in more complex cases you can escape using a macro. For instance for many sorts of objects which are normally not externalizable you can teach the system how to externalize them, and then splice the object in as a literal using #.:
(eval-when (:compile-toplevel :load-toplevel :execute)
;; Again, this would be in its own file in a bigger system
(defclass string-table-wrapper ()
((strings)
(nstrings :initform 0)))
(defmethod initialize-instance :after ((w string-table-wrapper)
&key (strings '()))
(let ((l (length strings)))
(when l
(with-slots ((s strings) (n nstrings)) w
(setf s (make-array l :initial-contents strings)
n l)))))
(defmethod make-load-form ((w string-table-wrapper) &optional environment)
(make-load-form-saving-slots w :slot-names '(strings nstrings)
:environment environment))
) ;eval-when
(defgeneric get-string (from n)
(:method ((from string-table-wrapper) (n fixnum))
(with-slots (strings nstrings) from
(assert (< -1 n nstrings )
(n)
"bad index")
(aref strings n))))
(defparameter *my-strings*
#.(make-instance 'string-table-wrapper
:strings '("foo" "bar")))
Note that, of course, although the value of *my-strings* is a literal, code ran to reconstruct this object at load-time. But that is always the case: it's just that in this case you had to define what code needed to run. Instead of using make-load-form-saving-slots you could have done this yourself, for instance by something like this:
(defmethod make-load-form ((w string-table-wrapper) &optional environment)
(declare (ignore environment))
(if (slot-boundp w 'strings)
(values
`(make-instance ',(class-of w))
`(setf (slot-value ,w 'strings)
',(slot-value w 'strings)
(slot-value ,w 'nstrings)
,(slot-value w 'nstrtrings)))
`(make-instance ',(class-of w))))
But make-load-form-saving-slots is much easier.
Here is an example where a macro does perhaps least make reading the code easier.
Let's assume you have a function which reads an array of strings from a file, for instance this:
(defun file-lines->svector (file)
;; Needs CL-PPCRE
(with-open-file (in file)
(loop
with ltw = (load-time-value
(create-scanner '(:alternation
(:sequence
:start-anchor
(:greedy-repetition 1 nil
:whitespace-char-class))
(:sequence
(:greedy-repetition 1 nil
:whitespace-char-class)
:end-anchor)))
t)
for nlines upfrom 0
for line = (read-line in nil)
while line
collect (regex-replace-all ltw line "") into lines
finally (return (make-array nlines :initial-contents lines)))))
Then, if this function is available at macroexpansion time, you could write this macro:
(defmacro file-strings-literal (file)
(check-type file (or string pathname) "pathname designator")
(file-lines->svector file))
And now we can create a literal vector of strings:
(defparameter *fl* (file-strings-literal "/tmp/x"))
However you could perfectly well instead do this:
(defparameter *fl* #.(file-lines->svector "/tmp/x"))
Which will do the same thing, but slightly earlier (at read time, rather than at macroexpansion/compile time). So this is gaining nothing really.
But you could also do this:
(defmacro define-stringtable (name file &optional (doc nil docp))
`(defparameter ,name ,(file-lines->svector file)
,#(if docp (list doc) nil)))
And now your code reads like
(define-stringtable *st* "my-stringtable.dat")
And that actually is a significant improvement.
Finally note that in file-lines->svector that load-time-value is used to create the scanner exactly once, at load time, which is a related trick.
First of all, your let code can be simplified to
(defparameter +global-vector-constant+
(let ((vector ...))
...
vector))
Second, you can also do
(defparameter +global-vector-constant+
(make-array 10 :element-type 'test-struct :initial-content
(cons (make-test-struct :str-1 "test-0-1" :str-2 "test-0-2")
(loop :repeat 9 :collect (make-test-struct)))))
Note that the benefit of :element-type 'test-struct is generally limited to code self-documentation (see upgraded-array-element-type)

In Common Lisp, how to test if variable is special?

I thought I would be able to find this through Google, SO, or the books I'm reading, but it is proving elusive.
In the implementation I'm learning with, I can do the following at the top-level:
(defvar *foo* 4)
(set 'bar 3)
If I then call (describe '*foo*) and (describe 'bar), I get a description saying that *foo* is special and bar is non-special (among other details).
Is there a function that takes a symbol variable as an argument and returns true or false if it is special? If so, is describe probably implemented in part by calling it?
Context: I'm learning Common Lisp, but at work I have a system with a dialect of Lisp similar to Common Lisp, but the describe function is unimplemented. There's sort of an XY thing going on here, but I'm also trying to grok Lisp and CL.
Many Common Lisp implementations provide the function variable-information in some system dependent package.
Here in SBCL:
* (require :sb-cltl2)
NIL
* (sb-cltl2:variable-information '*standard-output*)
:SPECIAL
NIL
((TYPE . STREAM))
This function was proposed as part of some other functionality to be included into ANSI CL, but didn't make it into the standard. Still many implementations have it. For documentation see: https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node102.html
A non-special variable's environment will be captured when you create a closure over it:
(let ((x 1))
(let ((f (lambda () x)))
(let ((x 2))
(eql 2 (funcall f)))))
;;=> NIL
A special variable's lexical environment will not:
(defvar *x*) ; *x* is special
(let ((*x* 1))
(let ((f (lambda () *x*)))
(let ((*x* 2))
(eql 2 (funcall f)))))
;;=> T
Using this approach, you could easily define a macro that will expand to code like the previous that will let you determine whether a symbol is globally proclaimed special:
(defmacro specialp (symbol)
(let ((f (gensym "FUNC-")))
`(let ((,symbol 1))
(let ((,f (lambda () ,symbol)))
(let ((,symbol 2))
(eql 2 (funcall ,f)))))))
(specialp x) ;=> NIL
(specialp *x*) ;=> T
Note that this isn't a function, it's a macro. That means that the macro function for specialp is getting called with the symbols X and *X*. This is important, because we have to construct code that uses these symbols. You can't do this with a function, because there'd be no (portable) way to take a symbol and create a lexical environment that has a lexical variable with that name and a lambda function that refers to it.
This also has some risks if you try to use it with certain symbols. For instance, in SBCL, if you try to bind, e.g., *standard-output* to something that isn't a stream or a stream designator, you'll get an error:
CL-USER> (specialp *standard-output*)
; in: SPECIALP *STANDARD-OUTPUT*
; (LET ((*STANDARD-OUTPUT* 1))
; (LET ((#:FUNC-1038 (LAMBDA # *STANDARD-OUTPUT*)))
; (LET ((*STANDARD-OUTPUT* 2))
; (EQL 2 (FUNCALL #:FUNC-1038)))))
;
; caught WARNING:
; Constant 1 conflicts with its asserted type STREAM.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition
Defining globals with set or setq is not supported. There are 2 common ways to define globals:
(defparameter *par* 20) ; notice the earmuffs in the name!
(defvar *var* 30) ; notice the earmuffs in the name!
All global variables are special. Lexically scoped variables (not special) are not possible to get described. E.g.
(let ((x 10))
(describe 'x)) ; ==> X is the symbol X
It describes not the lexical variable but the symbol representation. It really doesn't matter since you probably never need to know in run time since you know this when you're writing if it's a bound lexical variable or global special by conforming to the earmuffs naming convention for global variables.
I believe the only way to get this information at run time* is by either using an extension to CL, as Rainer noted, or to use eval.
(defun specialp (x)
(or (boundp x)
(eval `(let (,x)
(declare (ignorable ,x))
(boundp ',x)))))
(Defect warning: If the variable is unbound but declared to be a type incompatible with nil, this could raise an error. Thanks Joshua for pointing it out in his answer.)
* The macro approach determines which symbol it is checking at macro expansion time, and whether that symbol is lexical or special at compile time. That's fine for checking the status of a variable at the repl. If you wanted to e.g. print all of the special variables exported by a package, though, you would find that to use the macro version you would end up having to use eval at the call site:
(loop for s being the external-symbols of :cl-ppcre
when (eval `(specialp-macro ,s)) do (print s))

why (car ''(a b)) evaluated to 'quote?

I'm a beginner Scheme programmer and I want to enrich my knowledge in functional programming. I programm in DrRacket IDE. Recently I found some interesting piece of code:
(car ''(a b))
Output:
'quote
Can anyone explain me why is it evaluated in this way?
This is because ' is short for (quote ...). So,
(car ''(a b))
is actually
(car (quote (quote (a b))))
Which evaluates to:
'quote
As pointed out by Josh in the comments, The actual result is just quote And the REPL prints an expression that can evaluate to quote in this case 'quote or what is the same as seen above (quote quote).
Remember that 'x (for any expression x) is just shorthand for (quote x), so this code:
(car ''(a b))
Is equivalent to this one:
(car (quote (quote (a b))))
Now it's easy to see that you're evaluating the car of a list that looks like this:
'(quote (a b))
Which gets evaluated to this:
(list 'quote (list 'a 'b))
And if we take the car of the above line we'll get the symbol quote, which is precisely the result that you see printed.
It doesn't!
(car ''(a b))
Which is
(car (quote (quote (a b))))
What happens is that car get evaluated to #<procedure:car> and since it'a procedure every argument gets evaluated once before applying..
(quote (quote (a b))) ; ==> (quote (a b))
Now #<procedure:car> of (quote (a b)) is quote. It's not 'quote. I can prove it. Try wrapping it in display like this: (display (car ''(a b))). The output is just quote
So why do you see 'quote in racket interactions window?
Racket has a feature that you can tweak how data is displayed when the expression results that are not explicitly printed by your program. The standard depends on the language selected and for #!racket it's to not to display the data as is but something that you can evaluate and becomes the data. In the REPL you can evaluate the output and get the same since that mode is in effect.
You can change the behaviour if you choose Choose language in the bottom left select and press Show details. The part output syntax lets you choose amongst 4 ways to "display results" in the interactions window. print is the language default and write is the same you get as when you display the data and what is expected from most Scheme books.

Modifying a list passed as a parameter gives different results in SBCL and CLISP

Can someone explain why I get different results for the following simple program with sbcl and clisp? Is what I am doing undefined by the language, or is one of the two lisp interpreters wrong?
; Modify the car of the passed-in list
(defun modify (a) (setf (car a) 123))
; Create a list and print car before and after calling modify
(defun testit () (let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
(testit)
SBCL (version 1.0.51) produces:
0
0
CLISP (version 2.49) produces (what I would expect):
0
123
I agree with Seth's and Vsevolod's comments in that this behavior is due to your modification of literal data. Try using (list 0) instead of '(0). Questions relating to this come up relatively frequently, so I'll quote the HyperSpec here.
3.7.1 Modification of Literal Objects:
The consequences are undefined if literal objects are destructively
modified.
The definition of "literal":
literal adj. (of an object) referenced directly in a program rather
than being computed by the program; that is, appearing as data in a
quote form, or, if the object is a self-evaluating object, appearing
as unquoted data. ``In the form (cons "one" '("two")), the expressions
"one", ("two"), and "two" are literal objects.''
Note that often (in many implementations), if you modify literal values, you'll really modify them in the code itself – writing self modifying code. Your example code will not work as you expect.
Your example code in CCL:
CL-USER> (defun modify (a) (setf (car a) 123))
MODIFY
CL-USER> (defun testit ()
(let ((a '(0)))
(print (car a))
(modify a)
(print (car a))))
TESTIT
CL-USER> (testit)
0
123
123
CL-USER> (testit)
123
123
123
Take a look at the second evaluation of testit, where the let itself really already contains the modified value, thus the first print also yields 123.
Also see: Lisp, cons and (number . number) difference, where I explained this in more detail, or the question linked in Vsevolod's comment above.

Traversing Scheme function as a list

Isn't it possible to treat functions in Scheme as any other list?
Basically, what I want do to is something like this:
(define (foo) "hello")
(cdr foo) ; or similar, should return the list ((foo) "hello")
I've found a similar discussion about this, and I feel a bit disappointed if this is not possible with Scheme. If so, why is this impossible? Is it possible in other lisps?
EDIT: Changed (cdr 'foo) to (cdr foo) -- it was misleading. I'm asking, why can't I access a function as a list?
I have often wanted to be able to do the same thing csl.
Below is a quick example of how you could go about doing this in mzscheme.
DrScheme 4.2
(module qdefine mzscheme
(provide ;(all-from-except mzscheme let)
(rename define olddefine)
(rename quote-define define)
(rename quote-cdr cdr)
(rename quote-car car))
(define define-list '())
(define define-list-add
(lambda (key value)
(set! define-list (cons `(,key ,value) define-list))))
(define-syntax quote-define
(syntax-rules ()
((_ (pro-name args ...) body ...)
(begin
(define (pro-name args ...) body ...)
(define-list-add pro-name '((pro-name args ...) body ...))))
((_ pro-name pro) (begin
(define pro-name pro)
(define-list-add pro-name 'pro)))
))
(define quote-cdr (lambda (lst)
(if (procedure? lst)
(cdr (cadr (assoc lst define-list)))
(cdr lst))))
(define quote-car (lambda (lst)
(if (procedure? lst)
(car (cadr (assoc lst define-list)))
(car lst))))
)
(require 'qdefine)
(define testfunc (lambda (args) args))
(cdr testfunc)
(car testfunc)
(define (testfunc2 test) 'blah)
(cdr testfunc2)
(car testfunc2)
(define testlist '(1 2 3 4 5 6 'a))
(cdr testlist)
(car testlist)
Outputs:
((args) args)
lambda
('blah)
(testfunc2 test)
(2 3 4 5 6 'a)
1
>
Your define form is not a function but a function definition. In fact, it is a shorthand for
(define foo
(lambda ()
"hello"))
Lambda can be thought of as a "compiler invocation". In this case, it produces a function which returns that string. Define then binds this function to the symbol 'foo.
Compare this to
(define foo "hello")
which binds just the string to the symbol 'foo. What would (cdr foo) return?
Now, it is imaginable that some Scheme implementation actually saves or has the option to save the lambda form when binding a function to a symbol. You will have to check the documentation, but the kind of pure interpretation this implies surely would have an impact on performance.
If you manage to get this, though, it will return the lambda form, not the define form.
MIT Scheme has the ability to do this. (If you really want, comment on this and I'll give you the code. I had to find some undocumented functions to make it happen.)
However, it's not in the Scheme language definition, so implementations don't have to allow it. The reason for this is that in order to make functions faster, a good Scheme implementation will modify the functions. This means both rewriting them in a different language (either machine code or something fairly low-level) and taking out any bits you don't need - for instance, the + function must in general check whether its arguments are numbers, and if so, what sort of numbers, but if your function is a loop which calls +, you can just check once at the beginning, and make the function a lot faster.
Of course, you could still keep the lists around without too much trouble, even with all of these things. But if you tried to modify the lists, how would it work?
(Again, you could make it work. It would just be more work for implementers, and since it's not usually used in programs, most people probably just don't want to bother.)
In guile,
guile> (define (foo bar) 'baz)
guile> (procedure-source foo)
(lambda (bar) (quote baz))
guile> (cdr (procedure-source foo))
((bar) (quote baz))
guile>
'foo evaluates to a symbol, you can't take the CDR of a symbol.
What you may want to do is (cdr foo), but this does not work. The value of a FOO is a procedure, not a list.
You might be able to access the function as a list using pp or pretty-print. That said, you might also need to run your code in debug mode. This is very implementation dependent however. I know it can work in Gambit-C.
(define (foo) ...) produces a compiled object, and it's a value - a procedure.
You cannot iterate over it because it is not an s-expression.
Like what other suggested, you should check out your programming environment and see
if it has any facilities for such tasks.

Resources