Sourceable Representation
To use the bindings from this module:
(import :std/misc/repr)
print-representation
(print-representation obj
[port = (current-output-port)]
[options = (current-representation-options)]) -> void
obj := object to print
port := optional output port
options := hash-table, representation options
Prints an evaluable source-code representation of obj to port, which
defaults to (current-output-port)
. That very representation can later be read
and evaluated back into an equivalent object.
The behaviour of print-representation
can be specialized for new classes of
objects by defining new overloads on the :pr
method, see representable
.
Note: options aren't doing anything as of now, but are reserved for future
use. For instance, they may in the future be used to deal with circularity in
the object graph, which print-representation
does not currently handle.
The goal is that printing an object with print-representation
, pr
or prn
,
or capturing its output in a string with repr
, shall yield a representation
that if copy-pasted into the REPL in some reasonable context would yield
the same object as given as argument, up to equal?
.
In other words, the following equation should hold whenever possible,
(though it is obviously not guaranteed on arbitrary user-defined objects):
(equal? (eval (call-with-input-string (repr o) read)) o)
Now, if no other suitable method is found, an object with be printed using the
#42 #;"<foo #42>"
notation wherein a magic syntax using the "serial number"
syntax, that only works in the same context and same thread as the printer
for reading back, but still produces as much information as possible in a
subsequent #;
comment. You can use the #n
handle to query the object.
Examples:
> (import :std/sugar)
> (def lst (list 1 2 3))
> (def vec (vector 1 2 3))
> (def ht (hash (a 1) (b 2) (c 3)))
> (def fn string-append)
> (displayln lst)
(1 2 3)
> (print-representation lst)
[1 2 3] ; without newline, use prn for that
> (displayln vec)
#(1 2 3)
> (print-representation vec)
(vector 1 2 3)
> (displayln ht)
#<table #631>
> (print-representation ht)
(hash (a 1) (b 2) (c 3))
> (displayln fn)
#<procedure #632 string-append>
> (print-representation fn)
string-append
> (call-with-output-string (cut print-representation vec <>))
"(vector 1 2 3)"
> (repr vec) ; better use repr, which prints to string by default:
"(vector 1 2 3)"
> (with-output-to-file "hash.rep" (cut print-representation ht))
$ cat hash.rep ; unix-like command-line
(hash (a 1) (b 2) (c 3))%
> (with-input-from-file "hash.rep"
(lambda () (print-representation (eval (read)))))
(hash (a 1) (b 2) (c 3))
pr
(defalias pr print-representation)
Short for print-representation
.
Examples:
> (pr #(11 22 33))
(vector 11 22 33) ; without a newline
> (pr '((1 . x) (2 . y) (3 . z)))
[[1 'x ...] [2 'y ...] [3 'z ...]]
> (defstruct gerbil (name age greeting))
> (pr (make-gerbil "Cinnamon" 6 "Morning, everyone!"))
#634 #;"#<gerbil #634>" ; unrepresentable by default
prn
(prn obj [port = (current-output-port)]
[options = (current-representation-options)]) -> void
obj := object to print
port := optional output port
options := hash-table, representation options
prn
does the same as pr
or print-representation
, but also follows with a
newline.
Note: options aren't doing anything as of now, but are reserved for future use.
Examples:
> (import :std/sugar)
> (prn (hash-eqv (1 "I") (5 "V") (10 "X") (50 "L")))
(hash-eqv (1 "I") (10 "X") (5 "V") (50 "L")) ; proper newline at the end
> (prn [1 2 [3 4 [5 6 7] 8] 9])
[1 2 [3 4 [5 6 7] 8] 9]
repr
(repr obj [options = (current-representation-options)]) -> string
obj := object to print
options := hash-table, representation options
repr
is similar to print-representation
, but does not take a port as an
argument and instead returns the representation as a string.
Note: options aren't doing anything as of now, but are reserved for future use.
Examples:
> (defstruct node (data next prev))
> (repr (make-node #f #f #f))
"#635 #;\"#<node #635>\""
> (repr (node-data (make-node #(1 2 3) #f #f)))
"(vector 1 2 3)"
representable
(defclass representable ())
(defmethod {:pr representable} print-unrepresentable-object)
representable
is an abstract mixin class that defines a method for :pr
. By
default, if a class does not provide its own implementation, then
print-unrepresentable-object
will be called.
Examples:
> (defstruct point (x y))
> (def p (make-point 10 20))
> (displayln p)
#<point #4>
> (prn p)
#4 #;"#<point #4>" ; print-unrepresentable-object
> (import :std/format)
> (defmethod {:pr point}
(lambda (self port options)
(fprintf port "(point ~a ~a)"
(point-x self) (point-y self))))
> (prn p)
(point 10 20)
> (let ((p1 (make-point 10 20))
(p2 (eval (with-input-from-string (repr p) read))))
(and (= (point-x p1) (point-x p2))
(= (point-y p1) (point-y p2))))
#t
print-unrepresentable-object
(print-unrepresentable-object obj
[port = (current-output-port)]
[options = (current-representation-options)]) -> void
obj := object to print
port := optional output port
options := hash-table, representation options
print-unrepresentable-object
is a helper function to use as a fallback for
objects that can't otherwise be displayed. Prints a general-purpose escape of
obj, using the #id
syntax and appends a string hint as obtained from the
write
function.
Note: options aren't doing anything as of now, but are reserved for future use.
Examples:
> (import :std/misc/queue)
> (def q (make-queue))
> (enqueue! q 100)
> (prn q)
#9 #;"#<queue #9>" ; calls print-unrepresentable-object
> (print-unrepresentable-object q)
#9 #;"#<queue #9>"
display-separated
(display-separated lst
[port = (current-output-port)]
[prefix: ""]
[separator: " "]
[suffix: ""]
[display-element: display]) -> void
lst := list of objects to print
port := optional output port
prefix := string prefix
separator := string separator
suffix := string suffix
display-element := function that does the actual printing
display-separated
is a helper function that takes lst, a list of objects to
print, an optional output port, and as keywords a prefix string (empty by
default), a suffix string (empty by default), a separator string (defaulting
to a single space " "
), and a display-element function (display
by
default). Displays each element of lst with the given prefix, suffix,
separator and display-element function.
Examples:
> (import :std/sugar)
> (def ht (hash (a 1) (b 2) (c 3)))
> (display-separated (hash-values ht) (current-output-port)
prefix: "(list\n "
suffix: ")"
separator: "\n ")
(list
3
2
1)
;; this module already supports printing list:
> (prn (hash-values ht))
[3 2 1]