compatibility/collects/mzlib/pretty.ss
Matthew Flatt 466cdf0187 .
original commit: 77566789cee6d53331f69c6ccbf4a826d119f768
2004-08-24 16:25:06 +00:00

920 lines
26 KiB
Scheme

; Originally:
;"genwrite.scm" generic write used by pp.scm
;;copyright (c) 1991, marc feeley
; Pretty-printer for MzScheme
; Handles structures, cycles, and graphs
; TO INSTALL this pretty-printer into a MzScheme's read-eval-print loop,
; load this file and evaluate:
; (current-print pretty-print-handler)
;; Matthew's changes:
;; Modified original for MrEd Spring/95
;; Added check for cyclic structures 11/9/95
;; Better (correct) graph printing, support boxes and structures 11/26/95
;; Support for print depth 2/28/96
;; functor 4/22/96
;; unit/s 6/13/96
;; size- and print-hook 8/22/96
;; real parameters 9/27/96
;; print-line parameter 8/18/97
;; Added pretty-print-style 12/1/01
(module pretty mzscheme
(require)
(provide pretty-print
pretty-display
pretty-print-columns
pretty-print-depth
pretty-print-handler
pretty-print-size-hook
pretty-print-print-hook
pretty-print-pre-print-hook
pretty-print-post-print-hook
pretty-print-display-string-handler
pretty-print-print-line
pretty-print-show-inexactness
pretty-print-exact-as-decimal
pretty-print-.-symbol-without-bars
pretty-print-style-table?
pretty-print-current-style-table
pretty-print-extend-style-table)
(define-struct pretty-print-style-table (hash))
(define pretty-print-extend-style-table
(lambda (table symbols like-symbols)
(let ([terr (lambda (kind which)
(raise-type-error
'pretty-print-extend-style-table
kind
which
table symbols like-symbols))])
(unless (or (not table) (pretty-print-style-table? table))
(terr "pretty-print style table or #f" 0))
(unless (and (list? symbols)
(andmap symbol? symbols))
(terr "list of symbols" 1))
(unless (and (list? like-symbols)
(andmap symbol? like-symbols))
(terr "list of symbols" 1))
(unless (= (length symbols) (length like-symbols))
(raise-mismatch-error
'pretty-print-extend-style-table
(format "length of first list (~a) doesn't match the length of the second list (~a): "
(length symbols) (length like-symbols))
like-symbols)))
(let ([ht (if table (pretty-print-style-table-hash table) (make-hash-table))]
[new-ht (make-hash-table)])
(hash-table-for-each
ht
(lambda (key val)
(hash-table-put! new-ht key val)))
(for-each
(lambda (symbol like-symbol)
(let ((s (hash-table-get ht
like-symbol
(lambda () #f))))
(hash-table-put! new-ht symbol (or s like-symbol))))
symbols like-symbols)
(make-pretty-print-style-table new-ht))))
(define pretty-print-current-style-table
(make-parameter
(pretty-print-extend-style-table #f null null)
(lambda (s)
(unless (pretty-print-style-table? s)
(raise-type-error
'pretty-print-current-style-table
"pretty-print style table"
s))
s)))
(define pretty-print-.-symbol-without-bars
(make-parameter #f (lambda (x) (and x #t))))
(define pretty-print-show-inexactness
(make-parameter #f
(lambda (x) (and x #t))))
(define pretty-print-exact-as-decimal
(make-parameter #f
(lambda (x) (and x #t))))
(define pretty-print-columns
(make-parameter 79
(lambda (x)
(unless (or (eq? x 'infinity)
(integer? x))
(raise-type-error
'pretty-print-columns
"integer or 'infinity"
x))
x)))
(define pretty-print-depth
(make-parameter #f
(lambda (x)
(unless (or (not x) (number? x))
(raise-type-error
'pretty-print-depth
"number or #f"
x))
x)))
(define can-accept-n?
(lambda (n x)
(procedure-arity-includes? x n)))
(define pretty-print-size-hook
(make-parameter (lambda (x display? port) #f)
(lambda (x)
(unless (can-accept-n? 3 x)
(raise-type-error
'pretty-print-size-hook
"procedure of 3 arguments"
x))
x)))
(define pretty-print-print-hook
(make-parameter void
(lambda (x)
(unless (can-accept-n? 3 x)
(raise-type-error
'pretty-print-print-hook
"procedure of 3 arguments"
x))
x)))
(define pretty-print-display-string-handler
(make-parameter (let ([dh (port-display-handler (open-output-string))])
; dh is primitive port display handler
dh)
(lambda (x)
(unless (can-accept-n? 2 x)
(raise-type-error
'pretty-print-display-string-handler
"procedure of 2 arguments"
x))
x)))
(define pretty-print-print-line
(make-parameter (lambda (line port offset width)
(when (and (number? width)
(not (eq? 0 line)))
(newline port))
0)
(lambda (x)
(unless (can-accept-n? 4 x)
(raise-type-error
'pretty-print-print-line
"procedure of 4 arguments"
x))
x)))
(define pretty-print-pre-print-hook
(make-parameter void
(lambda (x)
(unless (can-accept-n? 2 x)
(raise-type-error
'pretty-print-pre-print-hook
"procedure of 2 arguments"
x))
x)))
(define pretty-print-post-print-hook
(make-parameter void
(lambda (x)
(unless (can-accept-n? 2 x)
(raise-type-error
'pretty-print-post-print-hook
"procedure of 2 arguments"
x))
x)))
(define make-pretty-print
(lambda (display?)
(letrec ([pretty-print
(case-lambda
[(obj port)
(let ([width (pretty-print-columns)]
[size-hook (pretty-print-size-hook)]
[print-hook (pretty-print-print-hook)]
[pre-hook (pretty-print-pre-print-hook)]
[post-hook (pretty-print-post-print-hook)])
(generic-write obj display?
width
(let ([display (pretty-print-display-string-handler)])
(lambda (s)
(display s port)
#t))
(lambda (s l)
(print-hook s display? port)
#t)
(print-graph) (print-struct) (print-hash-table)
(and (not display?) (print-vector-length))
(pretty-print-depth)
(lambda (o display?)
(size-hook o display? port))
(let ([print-line (pretty-print-print-line)])
(lambda (line offset)
(print-line line port offset width)))
(lambda (obj)
(pre-hook obj port))
(lambda (obj)
(post-hook obj port)))
(void))]
[(obj) (pretty-print obj (current-output-port))])])
pretty-print)))
(define pretty-print (make-pretty-print #f))
(define pretty-display (make-pretty-print #t))
(define-struct mark (str def))
(define pre-sym (gensym 'pre))
(define post-sym (gensym 'post))
(define (generic-write obj display? width output output-hooked
print-graph? print-struct? print-hash-table? print-vec-length?
depth size-hook print-line
pre-print post-print)
(define line-number 0)
(define table (make-hash-table)) ; Hash table for looking for loops
(define show-inexactness? (pretty-print-show-inexactness))
(define exact-as-decimal? (pretty-print-exact-as-decimal))
(define vector->repeatless-list
(if print-vec-length?
(lambda (v)
(let ([len (vector-length v)])
(if (zero? len)
null
(let ([last (vector-ref v (sub1 len))])
(let loop ([i (- len 2)])
(if (i . < . 0)
(list last)
(let ([e (vector-ref v i)])
(if (eq? e last)
(loop (sub1 i))
(let loop ([i (sub1 i)][r (list e last)])
(if (i . < . 0)
r
(loop (sub1 i) (cons (vector-ref v i) r))))))))))))
vector->list))
(define found-cycle
(or print-graph?
(let loop ([obj obj])
(and (or (vector? obj)
(pair? obj)
(box? obj)
(and (struct? obj) print-struct?)
(and (hash-table? obj) print-hash-table?))
(or (hash-table-get table obj (lambda () #f))
(begin
(hash-table-put! table obj #t)
(let ([cycle
(cond
[(vector? obj)
(let ([len (vector-length obj)])
(let loop ([i 0])
(if (= i len)
#f
(or (vector-ref obj i)
(loop (add1 i))))))]
[(pair? obj)
(or (loop (car obj))
(loop (cdr obj)))]
[(box? obj) (loop (unbox obj))]
[(struct? obj)
(ormap loop
(vector->list (struct->vector obj)))]
[(hash-table? obj)
(let/ec esc
(hash-table-for-each
obj
(lambda (v k)
(when (or (loop v)
(loop k))
(esc #t))))
#f)])])
(hash-table-remove! table obj)
cycle)))))))
(define :::dummy:::
(if found-cycle
(let loop ([obj obj])
(if (or (vector? obj)
(pair? obj)
(box? obj)
(and (struct? obj) print-struct?)
(and (hash-table? obj) print-hash-table?))
; A little confusing: use #t for not-found
(let ([p (hash-table-get table obj (lambda () #t))])
(when (not (mark? p))
(if p
(begin
(hash-table-put! table obj #f)
(cond
[(vector? obj)
(let ([len (vector-length obj)])
(let vloop ([i 0])
(unless (= i len)
(loop (vector-ref obj i))
(vloop (add1 i)))))]
[(pair? obj)
(loop (car obj))
(loop (cdr obj))]
[(box? obj) (loop (unbox obj))]
[(struct? obj)
(for-each loop
(vector->list (struct->vector obj)))]
[(hash-table? obj)
(hash-table-for-each
obj
(lambda (k v)
(loop k)
(loop v)))]))
(begin
(hash-table-put! table obj
(make-mark #f (box #f)))))))))))
(define cycle-counter 0)
(define found (if found-cycle
table
#f))
(define dsub1 (lambda (d)
(if d
(sub1 d)
#f)))
(print-line
#f
(let generic-write ([obj obj] [display? display?]
[width width]
[output output] [output-hooked output-hooked]
[depth depth] [def-box (box #t)]
[startpos (print-line 0 0)]
[pre-print pre-print] [post-print post-print])
(define (read-macro? l)
(define (length1? l) (and (pair? l) (null? (cdr l))))
(let ((head (car l)) (tail (cdr l)))
(case head
((quote quasiquote unquote unquote-splicing syntax)
(length1? tail))
(else #f))))
(define (read-macro-body l)
(cadr l))
(define (read-macro-prefix l)
(let ((head (car l)))
(case head
((quote) "'")
((quasiquote) "`")
((unquote) ",")
((unquote-splicing) ",@")
((syntax) "#'"))))
(define (out str col)
(and col (output str) (+ col (string-length str))))
(define expr-found
(lambda (ref col)
(let ([n cycle-counter])
(set! cycle-counter (add1 cycle-counter))
(set-mark-str! ref
(string-append "#"
(number->string n)
"#"))
(set-mark-def! ref def-box)
(out (string-append "#"
(number->string n)
"=")
col))))
(define check-expr-found
(lambda (obj check? col c-k d-k n-k)
(let ([ref (and check?
found
(hash-table-get found obj (lambda () #f)))])
(if (and ref (unbox (mark-def ref)))
(if c-k
(c-k (mark-str ref) col)
(out (mark-str ref) col))
(if (and ref d-k)
(d-k col)
(let ([col (if ref
(expr-found ref col)
col)])
(n-k col)))))))
(define (wr obj col depth)
(define (wr-expr expr col depth)
(if (read-macro? expr)
(wr (read-macro-body expr) (out (read-macro-prefix expr) col) depth)
(wr-lst expr col #t depth)))
(define (wr-lst l col check? depth)
(if (pair? l)
(check-expr-found
l check? col
#f #f
(lambda (col)
(if (and depth (zero? depth))
(out "(...)" col)
(let loop ((l (cdr l)) (col (wr (car l) (out "(" col) (dsub1 depth))))
(check-expr-found
l (and check? (pair? l)) col
(lambda (s col) (out ")" (out s (out " . " col))))
(lambda (col)
(out ")" (wr-lst l (out " . " col) check? (dsub1 depth))))
(lambda (col)
(and col
(cond
((pair? l)
(if (and (eq? (car l) 'unquote)
(pair? (cdr l))
(null? (cddr l)))
(out ")" (wr (cadr l) (out " . ," col) (dsub1 depth)))
(loop (cdr l) (wr (car l) (out " " col) (dsub1 depth)))))
((null? l) (out ")" col))
(else
(out ")" (wr l (out " . " col) (dsub1 depth))))))))))))
(out "()" col)))
(pre-print obj)
(begin0
(if (and depth (negative? depth))
(out "..." col)
(cond ((size-hook obj display?)
=> (lambda (len)
(and col
(output-hooked obj len)
(+ len col))))
((pair? obj) (wr-expr obj col depth))
((null? obj) (wr-lst obj col #f depth))
((vector? obj) (check-expr-found
obj #t col
#f #f
(lambda (col)
(wr-lst (vector->repeatless-list obj)
(let ([col (out "#" col)])
(if print-vec-length?
(out (number->string (vector-length obj)) col)
col))
#f depth))))
((box? obj) (check-expr-found
obj #t col
#f #f
(lambda (col)
(wr (unbox obj) (out "#&" col)
(dsub1 depth)))))
((struct? obj) (if (and print-struct?
(not (and depth
(zero? depth))))
(check-expr-found
obj #t col
#f #f
(lambda (col)
(wr-lst (vector->list
(struct->vector obj))
(out "#" col) #f
depth)))
(out
(let ([p (open-output-string)]
[p-s (print-struct)])
(when p-s
(print-struct #f))
((if display? display write) obj p)
(when p-s
(print-struct p-s))
(get-output-string p))
col)))
((hash-table? obj) (if (and print-hash-table?
(not (and depth
(zero? depth))))
(check-expr-found
obj #t col
#f #f
(lambda (col)
(wr-lst (hash-table-map obj cons)
(out "#hash" col) #f
depth)))
(out
(let ([p (open-output-string)]
[p-s (print-hash-table)])
(when p-s
(print-hash-table #f))
((if display? display write) obj p)
(when p-s
(print-hash-table p-s))
(get-output-string p))
col)))
((boolean? obj) (out (if obj "#t" "#f") col))
((number? obj)
(when (and show-inexactness?
(inexact? obj))
(out "#i" col))
(out ((if exact-as-decimal?
number->decimal-string
number->string)
obj) col))
((string? obj) (if display?
(out obj col)
(let ([p (open-output-string)])
(write obj p)
(let ([s (get-output-string p)])
(out s col)))))
((char? obj) (if display?
(out (make-string 1 obj) col)
(out
;; Must go through string to determe "printable" chars in any case:
(let ([p (open-output-string)])
(write obj p)
(get-output-string p))
col)))
((and display? (path? obj)) (out (path->string obj) col))
;; Let symbol get printed by default case to get proper quoting
;; ((symbol? obj) (out (symbol->string obj) col))
[(and (pretty-print-.-symbol-without-bars)
(eq? obj '|.|))
(out "." col)]
(else (out (let ([p (open-output-string)])
((if display? display write) obj p)
(get-output-string p))
col))))
(post-print obj)))
(define (pp obj col depth)
(define (spaces n col)
(if (> n 0)
(if (> n 7)
(spaces (- n 8) (out " " col))
(out (substring " " 0 n) col))
col))
(define (indent to col)
(and col
(if (< to col)
(and col
(begin
(set! line-number (add1 line-number))
(let ([col (print-line line-number col)])
(spaces (- to col) col))))
(spaces (- to col) col))))
(define (pr obj col extra pp-pair depth)
; may have to split on multiple lines
(let* ([can-multi (or (pair? obj) (vector? obj)
(box? obj)
(and (struct? obj) print-struct?)
(and (hash-table? obj) print-hash-table?))]
[ref (if can-multi
(and found (hash-table-get found obj (lambda () #f)))
#f)])
(if (and can-multi
(or (not ref) (not (unbox (mark-def ref)))))
(let* ((result '())
(result-tail #f)
(new-def-box (box #t))
(left (+ (- (- width col) extra) 1))
(snoc (lambda (s len)
(let ([v (cons s null)])
(if result-tail
(set-cdr! result-tail v)
(set! result v))
(set! result-tail v))
(set! left (- left len))
(> left 0))))
(generic-write obj display? #f
(lambda (s)
(snoc s (string-length s)))
(lambda (s l)
(snoc (cons s l) l))
depth
new-def-box
0
(lambda (obj)
(snoc (cons pre-sym obj) 0))
(lambda (obj)
(snoc (cons post-sym obj) 0)))
(if (> left 0) ; all can be printed on one line
(let loop ([result result][col col])
(if (null? result)
col
(loop (cdr result)
(+ (let ([v (car result)])
(if (pair? v)
(cond
[(eq? (car v) pre-sym)
(pre-print (cdr v))
col]
[(eq? (car v) post-sym)
(post-print (cdr v))
col]
[else
(output-hooked (car v) (cdr v))
(+ col (cdr v))])
(out (car result) col)))))))
(begin
(set-box! new-def-box #f)
(let ([col
(if ref
(expr-found ref col)
col)])
(pre-print obj)
(begin0
(cond
[(pair? obj) (pp-pair obj col extra depth)]
[(vector? obj)
(pp-list (vector->repeatless-list obj)
(let ([col (out "#" col)])
(if print-vec-length?
(out (number->string (vector-length obj)) col)
col))
extra pp-expr #f depth)]
[(struct? obj)
(pp-list (vector->list (struct->vector obj))
(out "#" col) extra pp-expr #f depth)]
[(hash-table? obj)
(pp-list (hash-table-map obj cons)
(out "#hash" col) extra pp-expr #f depth)]
[(box? obj)
(pr (unbox obj) (out "#&" col) extra pp-pair depth)])
(post-print obj))))))
(wr obj col depth))))
(define (pp-expr expr col extra depth)
(if (read-macro? expr)
(pr (read-macro-body expr)
(out (read-macro-prefix expr) col)
extra
pp-expr
depth)
(let ((head (car expr)))
(if (and (symbol? head)
(not (size-hook head display?)))
(let ((proc (style head)))
(if proc
(proc expr col extra depth)
(if (> (string-length (symbol->string head))
max-call-head-width)
(pp-general expr col extra #f #f #f pp-expr depth)
(pp-list expr col extra pp-expr #t depth))))
(pp-list expr col extra pp-expr #t depth)))))
; (head item1
; item2
; item3)
(define (pp-call expr col extra pp-item depth)
(let ((col* (wr (car expr) (out "(" col) (dsub1 depth))))
(and col
(pp-down (cdr expr) col* (+ col* 1) extra pp-item #t #t depth))))
; (head item1 item2
; item3
; item4)
(define (pp-two-up expr col extra pp-item depth)
(let ((col* (wr (car expr) (out "(" col) (dsub1 depth)))
(col*2 (wr (cadr expr) (out " " col) (dsub1 depth))))
(and col
(pp-down (cddr expr) (+ col 1) (+ col 2) extra pp-item #t #t depth))))
; (head item1
; item2
; item3)
(define (pp-one-up expr col extra pp-item depth)
(let ((col* (wr (car expr) (out "(" col) (dsub1 depth))))
(and col
(pp-down (cdr expr) (+ col 1) (+ col 2) extra pp-item #t #t depth))))
; (item1
; item2
; item3)
(define (pp-list l col extra pp-item check? depth)
(let ((col (out "(" col)))
(pp-down l col col extra pp-item #f check? depth)))
(define (pp-down l col1 col2 extra pp-item check-first? check-rest? depth)
(let loop ((l l) (col col1) (check? check-first?))
(and col
(check-expr-found
l (and check? (pair? l)) col
(lambda (s col)
(out ")" (out s (indent col2 (out "." (indent col2 col))))))
(lambda (col)
(out ")" (pr l (indent col2 (out "." (indent col2 col)))
extra pp-item depth)))
(lambda (col)
(cond ((pair? l)
(let ((rest (cdr l)))
(let ((extra (if (null? rest) (+ extra 1) 0)))
(loop rest
(pr (car l) (indent col2 col)
extra pp-item
(dsub1 depth))
check-rest?))))
((null? l)
(out ")" col))
(else
(out ")"
(pr l
(indent col2 (out "." (indent col2 col)))
(+ extra 1)
pp-item
(dsub1 depth))))))))))
(define (pp-general expr col extra named? pp-1 pp-2 pp-3 depth)
(define (tail1 rest col1 col2 col3)
(if (and pp-1 (pair? rest))
(let* ((val1 (car rest))
(rest (cdr rest))
(extra (if (null? rest) (+ extra 1) 0)))
(tail2 rest col1 (pr val1 (indent col3 col2) extra pp-1 depth) col3))
(tail2 rest col1 col2 col3)))
(define (tail2 rest col1 col2 col3)
(if (and pp-2 (pair? rest))
(let* ((val1 (car rest))
(rest (cdr rest))
(extra (if (null? rest) (+ extra 1) 0)))
(tail3 rest col1 (pr val1 (indent col3 col2) extra pp-2 depth)))
(tail3 rest col1 col2)))
(define (tail3 rest col1 col2)
(pp-down rest col2 col1 extra pp-3 #f #t depth))
(let* ((head (car expr))
(rest (cdr expr))
(col* (wr head (out "(" col) (dsub1 depth))))
(if (and named? (pair? rest))
(let* ((name (car rest))
(rest (cdr rest))
(col** (wr name (out " " col*) (dsub1 depth))))
(tail1 rest (+ col indent-general) col** (+ col** 1)))
(tail1 rest (+ col indent-general) col* (+ col* 1)))))
(define (pp-expr-list l col extra depth)
(pp-list l col extra pp-expr #t depth))
(define (pp-lambda expr col extra depth)
(pp-general expr col extra #f pp-expr-list #f pp-expr depth))
(define (pp-if expr col extra depth)
(pp-general expr col extra #f pp-expr #f pp-expr depth))
(define (pp-cond expr col extra depth)
(pp-list expr col extra pp-expr-list #t depth))
(define (pp-class expr col extra depth)
(pp-two-up expr col extra pp-expr-list depth))
(define (pp-make-object expr col extra depth)
(pp-one-up expr col extra pp-expr-list depth))
(define (pp-case expr col extra depth)
(pp-general expr col extra #f pp-expr #f pp-expr-list depth))
(define (pp-and expr col extra depth)
(pp-call expr col extra pp-expr depth))
(define (pp-let expr col extra depth)
(let* ((rest (cdr expr))
(named? (and (pair? rest) (symbol? (car rest)))))
(pp-general expr col extra named? pp-expr-list #f pp-expr depth)))
(define (pp-begin expr col extra depth)
(pp-general expr col extra #f #f #f pp-expr depth))
(define (pp-do expr col extra depth)
(pp-general expr col extra #f pp-expr-list pp-expr-list pp-expr depth))
; define formatting style (change these to suit your style)
(define indent-general 2)
(define max-call-head-width 5)
(define (style head)
(case (or (hash-table-get (pretty-print-style-table-hash
(pretty-print-current-style-table))
head
(lambda () #f))
head)
((lambda define define-macro define-syntax
syntax-rules
shared
unless when)
pp-lambda)
((if set! set!-values)
pp-if)
((cond case-lambda)
pp-cond)
((case)
pp-case)
((and or import export
require require-for-syntax require-for-template
provide link
public private override rename inherit field init)
pp-and)
((let letrec let*
let-values letrec-values let*-values
let-syntax letrec-syntax
let-syntaxes letrec-syntaxes)
pp-let)
((begin begin0)
pp-begin)
((do letrec-syntaxes+values)
pp-do)
((send class syntax-case instantiate module)
pp-class)
((make-object)
pp-make-object)
(else #f)))
(pr obj col 0 pp-expr depth))
(if (and width (not (eq? width 'infinity)))
(pp obj startpos depth)
(wr obj startpos depth)))))
(define pretty-print-handler
(lambda (v)
(unless (void? v)
(pretty-print v))))
(define (number->decimal-string x)
(cond
[(or (inexact? x)
(integer? x))
(number->string x)]
[(not (real? x))
(let ([r (real-part x)]
[i (imag-part x)])
(format "~a~a~ai"
(number->decimal-string r)
(if (negative? i)
""
"+")
(number->decimal-string i)))]
[else
(let ([n (numerator x)]
[d (denominator x)])
;; Count powers of 2 in denomintor
(let loop ([v d][2-power 0])
(if (and (positive? v)
(even? v))
(loop (arithmetic-shift v -1) (add1 2-power))
;; Count powers of 5 in denominator
(let loop ([v v][5-power 0])
(if (zero? (remainder v 5))
(loop (quotient v 5) (add1 5-power))
;; No more 2s or 5s. Anything left?
(if (= v 1)
;; Denominator = (* (expt 2 2-power) (expt 5 5-power)).
;; Print number as decimal.
(let* ([10-power (max 2-power 5-power)]
[scale (* (expt 2 (- 10-power 2-power))
(expt 5 (- 10-power 5-power)))]
[s (number->string (* (abs n) scale))]
[orig-len (string-length s)]
[len (max (add1 10-power) orig-len)]
[padded-s (if (< orig-len len)
(string-append
(make-string (- len orig-len) #\0)
s)
s)])
(format "~a~a.~a"
(if (negative? n) "-" "")
(substring padded-s 0 (- len 10-power))
(substring padded-s (- len 10-power) len)))
;; d has factor(s) other than 2 and 5.
;; Print as a fraction.
(number->string x)))))))]))
)