As you know Gambit has two pretty printing procedures which differ in the default output port:
(pp obj [port]) ;; port defaults to REPL output port (pretty-print obj [port]) ;; port defaults to current output port
The rationale is that pretty printing may be part of the program's normal behavior or be used for debugging. In the latter case you want the output to go to the REPL's output port (remember that stdout/ stderr could have been redirected by the user as part of the program's function so they can't be used for user interaction).
But I notice that I often need to pretty print more than one value, and I typically add labels to the values, for example:
(pp (list foo: foo bar: bar))
This is tedious. Moreover I often add a call to pp to print the result of a function, and I want the result to be returned so I end up transforming:
(define (square x) (* x x))
into
(define (square x) (let ((result (* x x))) (pp result) result))
So I'm thinking of transforming pp into a special form which automatically adds keyword labels (when no keyword is explicitly given) and returns the value of the last expression. So you could do
(define (square x) (pp x result: (* x x)))
and get as output:
x: 10 result: 100
Perhaps I shouldn't change pp and instead use a different short name, but which one? It could be a special symbol, for example:
(define (square x) (& x result: (* x x)))
But special symbols are in short supply and best left for future extensions and user needs. That's why I like pp. It is easy to type and the meaning is clear.
What do you think?
Marc
Afficher les réponses par date
Marc,
On Sun, Jun 1, 2008 at 9:21 AM, Marc Feeley feeley@iro.umontreal.ca wrote:
But special symbols are in short supply and best left for future extensions and user needs. That's why I like pp. It is easy to type and the meaning is clear.
What do you think?
This is probably flamebait, but... A solution to the symbol-shortage problem would be a module system :) which supported encapsulation and export of both variables and syntax forms. :)
--Jeff
Invoking the module system to gain access to pp (or its replacement) would be too heavy for debugging purposes. When I'm hunting a bug I want to add calls to pp with minimal effort. My message was all about changing pp to reduce the overhead further.
Marc
On 1-Jun-08, at 12:31 PM, Jeff Read wrote:
This is probably flamebait, but... A solution to the symbol-shortage problem would be a module system :) which supported encapsulation and export of both variables and syntax forms. :)
--Jeff
On Sun, Jun 1, 2008 at 5:21 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
But I notice that I often need to pretty print more than one value, and I typically add labels to the values, for example:
(pp (list foo: foo bar: bar))
This is tedious.
Actually I do much the same thing, except that I use the idiom
(pp `((foo ,foo) (bar ,bar)))
or more oftenly, I just use write/newline.
Moreover I often add a call to pp to print the result of a function, and I want the result to be returned so I end up transforming:
(define (square x) (* x x)) => (define (square x) (let ((result (* x x))) (pp result) result))
This *is* tedious, and I do it all the time, too.
So I'm thinking of transforming pp into a special form which automatically adds keyword labels (when no keyword is explicitly given) and returns the value of the last expression.
I did have this once in my personal standard-library. I called it IDEM-PRINT or some such stupid name. So yes, I think you;re looking at something which definitely falls into the 'nice-to-have' category.
Perhaps I shouldn't change pp and instead use a different short name, but which one?
I can't help you here, but PP and PRETTY-PRINT are widely implemented and have expected meanings to those of us who regularly use multiple Scheme implementations, so I would suggest that you find a different name, anyway.
What do you think?
There you have it.
david rush
On 1-Jun-08, at 2:47 PM, David Rush wrote:
I can't help you here, but PP and PRETTY-PRINT are widely implemented and have expected meanings to those of us who regularly use multiple Scheme implementations, so I would suggest that you find a different name, anyway.
Is portability a real concern? According to the Snow extio package Bigloo and MIT-Scheme use "pp" for pretty-printing, and don't define "pretty-print". Nine other systems use the name "pretty-print", most of which don't define "pp". So "pretty-print" would appear to be more portable. Moreover, Gambit's "pp" would still pretty print, but with added labels. One drawback is that you could no longer do (for-each pp lst) because pp would be a special form. Of course (for-each pretty-print lst) would work.
Marc
On Sun, Jun 1, 2008 at 8:49 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
On 1-Jun-08, at 2:47 PM, David Rush wrote:
I can't help you here, but PP and PRETTY-PRINT are widely implemented and have expected meanings to those of us who regularly use multiple Scheme implementations, so I would suggest that you find a different name, anyway.
Is portability a real concern? According to the Snow extio package Bigloo and MIT-Scheme use "pp" for pretty-printing, and don't define "pretty-print". Nine other systems use the name "pretty-print", most of which don't define "pp".
Well, I used to use Bigloo a lot, but I haven't done a formal survey. My standard compatibility prelude defines pp and pretty-print to be identical across systems in just the same way it also defines call/cc for those systems that implement only call-with-current-continuation. So no, it's not a big deal, I just thought I'd mention it.
david rush
Цитирую Marc Feeley feeley@iro.umontreal.ca:
(define (square x) (pp x result: (* x x)))
and get as output:
x: 10 result: 100
In Common Lisp I'd turned on tracing for SQUARE, which prints function arguments and results. I'm not much of a Gambit user, so I don't know whether TRACE machinery is in place; if not, it'd be worth-while to add it.
Cheers, Dmitri
On 1-Jun-08, at 3:34 PM, hrapof@common-lisp.ru wrote:
Цитирую Marc Feeley feeley@iro.umontreal.ca:
(define (square x) (pp x result: (* x x)))
and get as output:
x: 10 result: 100
In Common Lisp I'd turned on tracing for SQUARE, which prints function arguments and results. I'm not much of a Gambit user, so I don't know whether TRACE machinery is in place; if not, it'd be worth-while to add it.
Gambit has trace:
% gsi Gambit v4.2.8
(define (square x) (* x x)) (trace square) (square 10)
| > (square 10) | 100 100
In some cases you want to display additional information, like values computed by the procedure. So pp is more general.
Marc
On Sun, Jun 01, 2008 at 12:21:34PM -0400, Marc Feeley wrote:
What do you think?
Other people have made some interesting points. The one about standardization is worth repeating.
You may want to look at it from the users' point of view. I sometimes see this kind of feature which has already been decided, and which I can't change.
QuickBasic's and Python's "print" statements take a variable number of items and automatically put spaces between the printouts of the items. Then how to remove them? (Usually by putting everything in one argument, or using another form of print.) But if the print statement never inserts anything, then adding spaces (or anything else) to the arguments requires no drastic transformations.
I'm not just making an analogy. That little example touches on some interesting issues in language design.
From your own point of view as a language designer, have you thought of
how to combine the existing output-port syntax with the new syntax?
Or as a library and IDE designer, have you thought about your label feature as the beginning of an object inspector?
-- Derek
Hello Marc & co,
My reply is a bit long, but has two parts, a first about the |&| symbol, and a second about my ways to do "printf debugging". I care about the former part more, so if you skip parts of this message, please do so with the second.
Marc Feeley wrote:
Perhaps I shouldn't change pp and instead use a different short name, but which one? It could be a special symbol, for example:
(define (square x) (& x result: (* x x)))
I'm hoping that you won't use |&| for that, since I've long been using this symbol as a shortcut for creating a thunk.
(define-macro (& first . rest) `(lambda() ,first ,@rest))
The & seemed like the best character to me for that purpose;
- in Perl, it's the sigil for subroutine slots in the toplevel - in C, it's taking a pointer - in sh/bash, you use it for suspension of jobs
Ok, those are all not really the same thing. But still related to "suspending execution", to "taking a pointer to something" (give a pointer to code instead of executing it and giving the result); and Perl decided to designate the & for routines, so why shouldn't I do so too (regardless of Perl being ugly and possibly evil).
I've already started using a & as appendix to macros whose ~sole purpose is taking a thunk of their body; like
(define-macro (with-output-to-string& . body) `(with-output-to-string '() (lambda () ;; could have used & here of course, too ,@body)))
But special symbols are in short supply and best left for future extensions and user needs. That's why I like pp. It is easy to type and the meaning is clear.
What do you think?
I don't think I would ever have been bitten by pp not being a procedure, so I won't really care, but I'm not sure of the benefit either; |error| isn't a special form either, and there you've got some machinery for dealing with multiple values already. If you think you want to improve pp, you should improve error as well, or at least make their behaviour of creating the message string match. Now I think making error a macro would really not such a good idea, so I think the non-dieing counterpart of |error| should not be one either. But I've already choosen to call that counterpart something else already: warn. And for the purpuse of displaying a value while returning it, I'm using a procedure I'm calling pp-through.
Here they are:
(define no-value (gensym))
(define-bothtimes (pp-through a #!optional (b no-value)) (define port (current-output-port)) ;; hm ugly, during load, chjmodule outputs to stdout, so this is the ;; relevant port to print to. using current-error-port doesn't work ;; as intended. (if (> (output-port-column port) 1) (newline port)) (if (eq? b no-value) (begin (pp a port) a) (begin (display a port) (pp b port) b)))
(define (warn . l) ;; made it so that it acts the same as gambit's error (if (pair? l) (let ((p (current-error-port))) (display (car l) p) (let loop ((l (cdr l))) (if (pair? l) (begin (write-char #\space p) (write (car l) p) (loop (cdr l))) (newline p)))) (error "cj-env#warn called without arguments")))
(I must admit that I don't know anymore why I did put that "hm ugly" comment above.)
Here they are in action:
(list result: (warn "Hello" "World"))
Hello "World" (result: #!void)
(list result: (let ((i 1)(res '(4 3 2))) (warn "hey my values are:" i: i
res: res))) hey my values are: i: 1 res: (4 3 2) (result: #!void)
and
(list result: (pp-through '(hey "ya")))
(hey "ya") (result: (hey "ya"))
(list result: (pp-through foo: '(hey "ya")))
foo:(hey "ya") (result: (hey "ya"))
(list result: (pp-through "foo:" '(hey "ya")))
foo:(hey "ya") (result: (hey "ya"))
(I'm not sure why I don't emit a space after the first argument in pp-through, it would be consistent with |warn| to do so; but I'm using the two-argument form rarely anyway.)
I'm using |pp-through| for those cases where I want to show a value being returned (optionally with a description before it); that's especially the case in macros to show the code being generated.
I'm using |warn| for those "printf debugging" cases where I want to show some statement or one or more values as a side effect -- if this happens to be in a non-sequence position, this would need me to wrap it with a begin, like:
(let lp ((i 10) (res '())) (if (negative? i) i (begin (warn "in lp" i: i res: res) (lp (- i 1) (cons i res)))))
BTW note that in a case like this the warn couldn't be in return position anyway, so a "wrap-a-function-around" approach like pp-through wouldn't work. (Could you do it with a macro/special form? Not sensibly I think.)
For me that distinction between multi-value-print-capability-but- no-return-value and only-one-value-but-return-it works well enough. (The first case returning #!void may actually be a hint for cases where a warn statement is in a return position by accident.)
The only incentive to turn |warn| into a macro for me had been to automatically also show the source code position of the warn statement, like perl's warn does (unless perl's warn is given a message which ends in a newline, which suppresses the line number / file display), but I've not (yet) bothered enough to do that. And possibly it would be better done by inspecting the continuation of the warn call dynamically, not by making it syntax -- as long as warn is not in tail position (which it never should be) that would work, after all (and Perl did choose that dynamic approach, too, although since Perl doesn't have TCO, there's never a case where finding the location would fail).
What I can't do cleanly with |warn| (but neither can I do it with |error|) is putting some text later in the message, like:
(warn "Foo is" foo "while bar is actually" bar)
will output the third argument as quoted string, of course. So maybe taking this further, inevitably by making it a special form/macro, would be worthwhile. Maybe call it |warn&| then, and also offer an analogous |error&| form? I don't see that problem in the return-the-value case since there you usually don't have the need to put anything *after* the value. The only thing a macro would bring you in that latter case is to show the code which generated the value automatically, but if that code is a big form (as opposed to just a variable reference), it would clutter up the output.
Christian.
Christian Jaeger wrote:
(define-bothtimes (pp-through a #!optional (b no-value))
(I have missed to change |define-bothtimes| to |define|; it's been there to define that procedure also during compilation, since I've been using pp-through in macros in the same file; define-bothtimes is:
(define-macro (define-bothtimes . l) (let ((code `(define ,@l))) (eval code) code))
.)
On Sun, Jun 1, 2008 at 6:21 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
Perhaps I shouldn't change pp and instead use a different short name, but which one? It could be a special symbol, for example:
(define (square x) (& x result: (* x x)))
But special symbols are in short supply and best left for future extensions and user needs. That's why I like pp. It is easy to type and the meaning is clear.
Isn't this future extension? I haven't written that much code in gambit, but I use pp a lot, and kind of like it the way it is, so my suggestion is to find another name. But if you can't settle for a short good one then changing pp won't be the end of the world I guess.
/Joel
On 2-Jun-08, at 3:05 AM, Joel Borggrén-Franck wrote:
Isn't this future extension? I haven't written that much code in gambit, but I use pp a lot, and kind of like it the way it is, so my suggestion is to find another name. But if you can't settle for a short good one then changing pp won't be the end of the world I guess.
/Joel
I've thought about it some more and pp's status as a procedure is too valuable, so pp will stay as is. So perhaps "debug" is the best name... it's just so long to type!
Marc
Marc Feeley wrote:
I've thought about it some more and pp's status as a procedure is too valuable, so pp will stay as is. So perhaps "debug" is the best name... it's just so long to type!
What about relying on case sensivity and using uppercase |PP| ? That would also have the benefit that one could switch between the old and new pp with the hit of a key (m-u and m-l in emacs).
Christian.
(BTW talking about emacs, I've long wanted an emacs procedure taking a symbol string as argument which wraps the form at point with some other form (putting the argument into the first position; so you could make a keybinding which just wraps (foo ) around the form (or region) at point. foo being debug if you don't want to go case sensitive. Should be easy enough but I'm not good in programming emacs.)
On Mon, Jun 2, 2008 at 3:25 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
On 2-Jun-08, at 3:05 AM, Joel Borggrén-Franck wrote:
Isn't this future extension? I haven't written that much code in gambit, but I use pp a lot, and kind of like it the way it is, so my suggestion is to find another name. But if you can't settle for a short good one then changing pp won't be the end of the world I guess.
I've thought about it some more and pp's status as a procedure is too valuable, so pp will stay as is. So perhaps "debug" is the best name... it's just so long to type!
You can always rip out some vowels :)
Some suggestions:
dbg ppd dout
/Joel