remove unstable/cat (use racket/format instead)
This commit is contained in:
parent
0252207e38
commit
9762e3f895
|
@ -1,459 +0,0 @@
|
|||
#lang racket/base
|
||||
(require racket/contract/base)
|
||||
|
||||
;; cat = "consider as text" :)
|
||||
|
||||
;; TO DO:
|
||||
;; - avoid unnecessary intermediate strings
|
||||
;; - see "Printing Floating-Point Numbers Quickly and Accurately"
|
||||
;; by Berger & Dybvig, PLDI 1996 for ideas
|
||||
|
||||
;; MAYBE TO DO:
|
||||
;; - rename 'cat' -> 'catd' ("cat like display") and make 'cat'
|
||||
;; recur into lists, vectors, etc?
|
||||
;; - decimal separators (see "man 7 locale", lconv numeric fields)
|
||||
;; - 'catmon' : like 'catn' but for monetary amounts (see strfmon)?
|
||||
;; (perhaps as separate library)
|
||||
;; - prop:cat, separate from prop:custom-write?
|
||||
|
||||
(define (non-empty-string? x)
|
||||
(and (string? x) (positive? (string-length x))))
|
||||
|
||||
(define align-mode/c
|
||||
(or/c 'left 'right 'center))
|
||||
(define padding/c non-empty-string?)
|
||||
|
||||
(define sign-mode/c
|
||||
(or/c #f '+ '++ 'parens
|
||||
(let ([ind/c (or/c string? (list/c string? string?))])
|
||||
(list/c ind/c ind/c ind/c))))
|
||||
|
||||
(define base/c
|
||||
(or/c (integer-in 2 36)
|
||||
(list/c 'up (integer-in 2 36))))
|
||||
|
||||
;; Precision is one of
|
||||
;; - Nat, for "up to N"
|
||||
;; - '(= N), for "exactly N"
|
||||
(define precision/c
|
||||
(or/c exact-nonnegative-integer?
|
||||
(list/c '= exact-nonnegative-integer?)))
|
||||
|
||||
(define cat-n-c
|
||||
(->* ()
|
||||
(#:width (or/c exact-nonnegative-integer? #f)
|
||||
#:limit (or/c exact-nonnegative-integer? +inf.0)
|
||||
#:limit-marker string?
|
||||
#:pad-to exact-nonnegative-integer?
|
||||
#:align align-mode/c
|
||||
#:padding padding/c
|
||||
#:left-padding padding/c
|
||||
#:right-padding padding/c)
|
||||
#:rest list?
|
||||
string?))
|
||||
|
||||
(define cat-1-c
|
||||
(->* (any/c)
|
||||
(#:width (or/c exact-nonnegative-integer? #f)
|
||||
#:limit (or/c exact-nonnegative-integer? +inf.0)
|
||||
#:limit-marker string?
|
||||
#:pad-to exact-nonnegative-integer?
|
||||
#:align align-mode/c
|
||||
#:padding padding/c
|
||||
#:left-padding padding/c
|
||||
#:right-padding padding/c)
|
||||
string?))
|
||||
|
||||
(provide/contract
|
||||
[cat cat-n-c]
|
||||
[catw cat-1-c]
|
||||
[catp cat-1-c]
|
||||
[catn
|
||||
(->* (rational?)
|
||||
(#:sign sign-mode/c
|
||||
#:base base/c
|
||||
#:precision precision/c
|
||||
#:pos/exp-range (list/c (or/c exact-integer? +inf.0)
|
||||
(or/c exact-integer? -inf.0))
|
||||
#:exp-precision precision/c
|
||||
#:exp-format-exponent (or/c #f string? (-> exact-integer? string?))
|
||||
#:pad-digits-to exact-positive-integer?
|
||||
#:digits-padding padding/c)
|
||||
string?)]
|
||||
[catnp
|
||||
(->* (rational?)
|
||||
(#:sign sign-mode/c
|
||||
#:base base/c
|
||||
#:precision precision/c
|
||||
#:pad-digits-to exact-positive-integer?
|
||||
#:digits-padding padding/c)
|
||||
string?)]
|
||||
[catne
|
||||
(->* (rational?)
|
||||
(#:sign sign-mode/c
|
||||
#:base base/c
|
||||
#:precision precision/c
|
||||
#:format-exponent (or/c #f string? (-> exact-integer? string?))
|
||||
#:pad-digits-to exact-positive-integer?
|
||||
#:digits-padding padding/c)
|
||||
string?)])
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
(define (%limit #:limit limit
|
||||
#:limit-marker limit-marker
|
||||
s)
|
||||
(cond [(> (string-length s) limit)
|
||||
(string-append (substring s 0 (- limit (string-length limit-marker)))
|
||||
limit-marker)]
|
||||
[else s]))
|
||||
|
||||
(define (%pad #:pad-to pad-to
|
||||
#:align align-mode
|
||||
#:left-padding left-padding
|
||||
#:right-padding right-padding
|
||||
s)
|
||||
(cond [(< (string-length s) pad-to)
|
||||
(let* ([s-length (string-length s)]
|
||||
[to-pad-length (max 0 (- pad-to s-length))])
|
||||
(let-values ([(left-pad-length right-pad-length)
|
||||
(case align-mode
|
||||
((left) (values 0 to-pad-length))
|
||||
((right) (values to-pad-length 0))
|
||||
((center)
|
||||
(values (floor (/ to-pad-length 2))
|
||||
(ceiling (/ to-pad-length 2)))))])
|
||||
(string-append
|
||||
(build-padding 'left left-padding left-pad-length)
|
||||
s
|
||||
(build-padding 'right right-padding right-pad-length))))]
|
||||
[else s]))
|
||||
|
||||
(define (build-padding side padding pad-length)
|
||||
(cond [(zero? pad-length) ""]
|
||||
[(char? padding)
|
||||
(make-string pad-length padding)]
|
||||
[(and (string? padding) (= (string-length padding) 1))
|
||||
(make-string pad-length (string-ref padding 0))]
|
||||
[(string? padding)
|
||||
(let* ([pattern padding]
|
||||
[pattern-length (string-length pattern)]
|
||||
[whole-copies (quotient pad-length pattern-length)]
|
||||
[part-length (remainder pad-length pattern-length)]
|
||||
[pattern-copies (for/list ([i (in-range whole-copies)]) pattern)])
|
||||
(apply string-append
|
||||
;; For left, start at start of string
|
||||
;; For right, end at end of string.
|
||||
(case side
|
||||
((left)
|
||||
(append pattern-copies
|
||||
(list (substring pattern 0 part-length))))
|
||||
((right)
|
||||
(cons (substring pattern (- pattern-length part-length) pattern-length)
|
||||
pattern-copies)))))]))
|
||||
|
||||
(define (do-checks who limit limit-marker width)
|
||||
(when (> width limit)
|
||||
(error who "pad-to length greater than limit (~s): ~s" limit width))
|
||||
(when (> (string-length limit-marker) limit)
|
||||
(error who "limit-marker string longer than limit (~s): ~e"
|
||||
limit limit-marker)))
|
||||
|
||||
;; ----------------------------------------
|
||||
|
||||
(define (%cat s
|
||||
#:who who
|
||||
#:limit limit
|
||||
#:limit-marker limit-marker
|
||||
#:pad-to pad-to
|
||||
#:align align
|
||||
#:right-padding right-padding
|
||||
#:left-padding left-padding)
|
||||
(do-checks who limit limit-marker pad-to)
|
||||
(%pad (%limit (if (list? s) (apply string-append s) s)
|
||||
#:limit limit
|
||||
#:limit-marker limit-marker)
|
||||
#:pad-to pad-to
|
||||
#:align align
|
||||
#:left-padding left-padding
|
||||
#:right-padding right-padding))
|
||||
|
||||
(define (cat #:width [width #f]
|
||||
;; I was greatly tempted to name this keyword option #:nip instead
|
||||
;; (or maybe #:nip-to)
|
||||
#:limit [limit (or width +inf.0)]
|
||||
#:limit-marker [limit-marker "..."]
|
||||
#:pad-to [pad-to (or width 0)]
|
||||
#:align [align 'left]
|
||||
#:padding [padding " "]
|
||||
#:right-padding [right-padding padding]
|
||||
#:left-padding [left-padding padding]
|
||||
. vs)
|
||||
(%cat (map (lambda (v) (if (string? v) v (format "~a" v))) vs)
|
||||
#:who 'cat
|
||||
#:limit limit
|
||||
#:limit-marker limit-marker
|
||||
#:pad-to pad-to
|
||||
#:align align
|
||||
#:right-padding right-padding
|
||||
#:left-padding left-padding))
|
||||
|
||||
(define (catw #:width [width #f]
|
||||
#:limit [limit (or width +inf.0)]
|
||||
#:limit-marker [limit-marker "..."]
|
||||
#:pad-to [pad-to (or width 0)]
|
||||
#:align [align 'left]
|
||||
#:padding [padding " "]
|
||||
#:right-padding [right-padding padding]
|
||||
#:left-padding [left-padding padding]
|
||||
v)
|
||||
(%cat (format "~s" v)
|
||||
#:who 'catw
|
||||
#:limit limit
|
||||
#:limit-marker limit-marker
|
||||
#:pad-to pad-to
|
||||
#:align align
|
||||
#:right-padding right-padding
|
||||
#:left-padding left-padding))
|
||||
|
||||
(define (catp #:width [width #f]
|
||||
#:limit [limit (or width +inf.0)]
|
||||
#:limit-marker [limit-marker "..."]
|
||||
#:pad-to [pad-to (or width 0)]
|
||||
#:align [align 'left]
|
||||
#:padding [padding " "]
|
||||
#:right-padding [right-padding padding]
|
||||
#:left-padding [left-padding padding]
|
||||
v)
|
||||
(%cat (format "~v" v)
|
||||
#:who 'cat
|
||||
#:limit limit
|
||||
#:limit-marker limit-marker
|
||||
#:pad-to pad-to
|
||||
#:align align
|
||||
#:right-padding right-padding
|
||||
#:left-padding left-padding))
|
||||
|
||||
;; ----
|
||||
|
||||
(define (catn N
|
||||
#:sign [sign-mode #f]
|
||||
#:base [base 10]
|
||||
#:precision [precision 3]
|
||||
#:pos/exp-range [pos/exp-range #f]
|
||||
#:exp-precision [exp-precision 5]
|
||||
#:exp-format-exponent [exp-format-exponent #f]
|
||||
#:pad-digits-to [pad-digits-to 1]
|
||||
#:digits-padding [digits-padding " "])
|
||||
(let* ([N-abs (abs N)]
|
||||
[positional?
|
||||
(or (zero? N-abs)
|
||||
(not pos/exp-range)
|
||||
(let ([max-neg-exp (car pos/exp-range)]
|
||||
[min-pos-exp (cadr pos/exp-range)])
|
||||
(< (expt base max-neg-exp) N-abs (expt base min-pos-exp))))])
|
||||
(if positional?
|
||||
(catnp N
|
||||
#:who 'catn
|
||||
#:sign sign-mode
|
||||
#:base base
|
||||
#:precision precision
|
||||
#:pad-digits-to pad-digits-to
|
||||
#:digits-padding digits-padding)
|
||||
(catne N
|
||||
#:who 'catn
|
||||
#:sign sign-mode
|
||||
#:base base
|
||||
#:precision exp-precision
|
||||
#:format-exponent exp-format-exponent
|
||||
#:pad-digits-to pad-digits-to
|
||||
#:digits-padding digits-padding))))
|
||||
|
||||
(define (catnp N
|
||||
#:who [who 'catnp]
|
||||
#:sign [sign-mode #f]
|
||||
#:base [base 10]
|
||||
#:precision [precision 3]
|
||||
#:pad-digits-to [pad-digits-to 1]
|
||||
#:digits-padding [digits-padding " "])
|
||||
;; precision: up to (or exactly) this many digits after decimal point
|
||||
;; precision = 0 means no decimal point
|
||||
;; precision = '(= 0) means keep decimal point
|
||||
;; pad-digits-to: includes decimal point, doesn't include sign
|
||||
(let*-values ([(upper? base) (normalize-base base)]
|
||||
[(exactly? precision) (normalize-precision precision)])
|
||||
(let* ([N-abs (abs N)]
|
||||
[digits-part (%positional N-abs base upper? precision exactly?)]
|
||||
[padded-digits-part
|
||||
(%pad digits-part
|
||||
#:pad-to pad-digits-to
|
||||
#:align 'right
|
||||
#:left-padding digits-padding
|
||||
#:right-padding #f)])
|
||||
(let-values ([(pre-sign-part post-sign-part) (get-sign-parts N sign-mode)])
|
||||
(string-append pre-sign-part padded-digits-part post-sign-part)))))
|
||||
|
||||
(define (catne N
|
||||
#:who [who 'catne]
|
||||
#:sign [sign-mode #f]
|
||||
#:base [base 10]
|
||||
#:precision [precision 5]
|
||||
#:format-exponent [format-exponent #f]
|
||||
#:pad-digits-to [pad-digits-to 1]
|
||||
#:digits-padding [digits-padding " "])
|
||||
(let*-values ([(upper? base) (normalize-base base)]
|
||||
[(exactly? precision) (normalize-precision precision)])
|
||||
(let* ([N-abs (abs N)]
|
||||
[digits-part
|
||||
(%exponential N-abs base format-exponent precision exactly?)]
|
||||
[padded-digits-part
|
||||
(%pad digits-part
|
||||
#:pad-to pad-digits-to
|
||||
#:align 'right
|
||||
#:left-padding digits-padding
|
||||
#:right-padding #f)])
|
||||
(let-values ([(pre-sign-part post-sign-part) (get-sign-parts N sign-mode)])
|
||||
(string-append pre-sign-part padded-digits-part post-sign-part)))))
|
||||
|
||||
(define (normalize-base base)
|
||||
(if (pair? base)
|
||||
(values (eq? (car base) 'up) (cadr base))
|
||||
(values #f base)))
|
||||
|
||||
(define (normalize-precision precision)
|
||||
(if (pair? precision)
|
||||
(values #t (cadr precision))
|
||||
(values #f precision)))
|
||||
|
||||
(define (%positional N-abs base upper? precision exactly?)
|
||||
(let* ([Nw (inexact->exact (floor N-abs))]
|
||||
[Nf (- N-abs Nw)]
|
||||
[whole-part (number->string* Nw base upper?)]
|
||||
[frac-part
|
||||
(let* ([Nf* (inexact->exact (round (* Nf (expt base precision))))])
|
||||
(cond [(and exactly? (= precision 0)) ""]
|
||||
[exactly? (number->fraction-string Nf* base upper? precision)]
|
||||
[(= Nf* 0) #f]
|
||||
[else
|
||||
(let-values ([(needed-precision Nf**)
|
||||
(let loop ([np precision] [Nf* Nf*])
|
||||
(let-values ([(q r) (quotient/remainder Nf* base)])
|
||||
(cond [(zero? r) (loop (sub1 np) q)]
|
||||
[else (values np Nf*)])))])
|
||||
(number->fraction-string Nf** base upper? needed-precision))]))]
|
||||
[digits-part
|
||||
(cond [frac-part (string-append whole-part "." frac-part)]
|
||||
[else whole-part])])
|
||||
digits-part))
|
||||
|
||||
(define (%exponential N-abs base format-exponent significand-precision exactly?)
|
||||
(define-values (N* e-adjust actual-precision)
|
||||
(scale N-abs base significand-precision exactly?))
|
||||
;; hack: from 1234 want "1.234"; convert to "1234", mutate to ".234" after saving "1"
|
||||
(let* ([digits (number->string* N* base #f)]
|
||||
[leading-digit (string (string-ref digits 0))]
|
||||
[exponent (- significand-precision e-adjust)])
|
||||
(string-set! digits 0 #\.)
|
||||
(string-append leading-digit
|
||||
(if (or exactly? (positive? actual-precision)) digits "")
|
||||
(cond [(procedure? format-exponent)
|
||||
(format-exponent exponent)]
|
||||
[else
|
||||
(string-append
|
||||
(cond [(string? format-exponent) format-exponent]
|
||||
[(= base 10) "e"]
|
||||
[else (format "×~s^" base)])
|
||||
(if (negative? exponent) "-" "+")
|
||||
(%pad (number->string (abs exponent))
|
||||
#:pad-to 2
|
||||
#:align 'right
|
||||
#:left-padding "0"
|
||||
#:right-padding #f))]))))
|
||||
|
||||
(define (scale N-abs base significand-precision exactly?)
|
||||
(if (zero? N-abs)
|
||||
(values 0 0 (if exactly? significand-precision 0))
|
||||
(scale/nz N-abs base significand-precision exactly?)))
|
||||
|
||||
(define (scale/nz N-abs base significand-precision exactly?)
|
||||
(let* ([N (inexact->exact N-abs)]
|
||||
[normalized-min (expt base significand-precision)]
|
||||
[normalized-max (* base normalized-min)])
|
||||
(let*-values ([(N*0 e-adjust0)
|
||||
(let ([e-est (- significand-precision
|
||||
(inexact->exact (floor (/ (log N-abs) (log base)))))])
|
||||
(values (* N (expt base e-est)) e-est))]
|
||||
[(N* e-adjust)
|
||||
(let loop ([N N*0] [e e-adjust0] [r #f])
|
||||
;; if r != #f, then N is integer
|
||||
(cond [(< N normalized-min)
|
||||
(loop (* N base) (add1 e) #f)]
|
||||
[(>= N normalized-max)
|
||||
(let-values ([(q r) (quotient/remainder (floor N) base)])
|
||||
(loop q (sub1 e) r))]
|
||||
[else
|
||||
(let ([N* (if r
|
||||
(if (>= (* 2 r) base) (add1 N) N)
|
||||
(round* N))])
|
||||
(cond [(< N* normalized-max)
|
||||
(values N* e)]
|
||||
[else (loop N* e #f)]))]))]
|
||||
[(N* actual-precision)
|
||||
(if exactly?
|
||||
(values N* significand-precision)
|
||||
(let loop ([N N*] [p significand-precision])
|
||||
(let-values ([(q r) (quotient/remainder N base)])
|
||||
(cond [(zero? r) (loop q (sub1 p))]
|
||||
[else (values N p)]))))])
|
||||
(values N* e-adjust actual-precision))))
|
||||
|
||||
;; ----
|
||||
|
||||
(define (get-sign-parts N sign-mode)
|
||||
(define (get indicator)
|
||||
(if (string? indicator)
|
||||
(values indicator "")
|
||||
(values (car indicator) (cadr indicator))))
|
||||
(let ([indicator-table
|
||||
(case sign-mode
|
||||
((#f) '("" "" "-"))
|
||||
((+) '("+" "" "-"))
|
||||
((++) '("+" "+" "-"))
|
||||
((parens) '("" "" ("(" ")")))
|
||||
(else sign-mode))])
|
||||
(cond [(or (negative? N) (eqv? -0.0 N))
|
||||
(get (caddr indicator-table))]
|
||||
[(zero? N)
|
||||
(get (cadr indicator-table))]
|
||||
[else ;; positive
|
||||
(get (car indicator-table))])))
|
||||
|
||||
(define (number->string* N base upper?)
|
||||
(cond [(memv base '(2 8 10 16))
|
||||
(let ([s (number->string N base)])
|
||||
(if (and (= base 16) upper?)
|
||||
(string-upcase s)
|
||||
s))]
|
||||
[(zero? N)
|
||||
(string #\0)]
|
||||
[else
|
||||
(apply string
|
||||
(let loop ([N N] [digits null])
|
||||
(cond [(zero? N) (reverse digits)]
|
||||
[else (let-values ([(q r) (quotient/remainder N base)])
|
||||
(loop q (cons (get-digit r upper?) digits)))])))]))
|
||||
|
||||
(define (number->fraction-string N base upper? precision)
|
||||
(let ([s (number->string* N base upper?)])
|
||||
(string-append (make-string (- precision (string-length s)) #\0) s)))
|
||||
|
||||
;; Allow base up to 36!
|
||||
(define (get-digit d upper?)
|
||||
(cond [(< d 10) (integer->char (+ d (char->integer #\0)))]
|
||||
[else (integer->char (+ (- d 10) (char->integer (if upper? #\A #\a))))]))
|
||||
|
||||
(define (round* x) ;; round is round-to-even :(
|
||||
(if (integer? x)
|
||||
x
|
||||
(+ (truncate x)
|
||||
(if (even? (truncate (+ x x))) 0 1))))
|
|
@ -1,472 +0,0 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/struct
|
||||
scribble/eval
|
||||
(for-label racket/base
|
||||
racket/contract
|
||||
racket/math
|
||||
unstable/cat
|
||||
unstable/contract))
|
||||
|
||||
@(begin
|
||||
(define the-eval (make-base-eval))
|
||||
(the-eval '(require racket/math unstable/cat)))
|
||||
|
||||
@title[#:tag "cat"]{Converting Values to Strings}
|
||||
@author[@author+email["Ryan Culpepper" "ryanc@racket-lang.org"]]
|
||||
|
||||
@defmodule[unstable/cat]
|
||||
|
||||
This module provides a few functions for converting Racket values to strings. In
|
||||
addition to features like padding and numeric formatting, the functions have the
|
||||
virtue of being shorter and more pleasant to type than @racket[format] (with
|
||||
format string), @racket[number->string], or @racket[string-append].
|
||||
|
||||
@defproc[(cat [v any/c] ...
|
||||
[#:width width (or/c exact-nonnegative-integer? #f) #f]
|
||||
[#:limit limit (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
|
||||
[#:limit-marker limit-marker string? "..."]
|
||||
[#:pad-to pad-to exact-nonnegative-integer? (or width 0)]
|
||||
[#:align align (or/c 'left 'center 'right) 'left]
|
||||
[#:padding padding non-empty-string? " "]
|
||||
[#:left-padding left-padding non-empty-string? padding]
|
||||
[#:right-padding right-padding non-empty-string? padding])
|
||||
string?]{
|
||||
|
||||
Converts each @racket[v] to a string in @racket[display] mode---that
|
||||
is, like @racket[(format "~a" v)]---then concatentates the results and
|
||||
pads or truncates the string to be at least @racket[pad-to] characters
|
||||
and at most @racket[limit] characters.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(cat "north")
|
||||
(cat 'south)
|
||||
(cat #"east")
|
||||
(cat #\w "e" 'st)
|
||||
(cat (list "red" 'green #"blue"))
|
||||
(cat 17)
|
||||
(cat #e1e20)
|
||||
(cat pi)
|
||||
(cat (expt 6.1 87))
|
||||
]
|
||||
|
||||
The @racket[cat] function is primarily useful for strings, numbers, and other
|
||||
atomic data. The @racket[catp] and @racket[catw] functions are better suited to
|
||||
compound data.
|
||||
|
||||
Let @racket[_s] be the concatenated string forms of the
|
||||
@racket[v]s. If @racket[_s] is longer than @racket[limit] characters,
|
||||
it is truncated to exactly @racket[limit] characters. If @racket[_s]
|
||||
is shorter than @racket[pad-to] characters, it is padded to exactly
|
||||
@racket[pad-to] characters. Otherwise @racket[_s] is returned
|
||||
unchanged. If @racket[pad-to] is greater than @racket[limit], an
|
||||
exception is raised.
|
||||
|
||||
If @racket[_s] is longer than @racket[limit] characters, it is truncated and the
|
||||
end of the string is replaced with @racket[limit-marker]. If
|
||||
@racket[limit-marker] is longer than @racket[limit], an exception is raised.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(cat "abcde" #:limit 5)
|
||||
(cat "abcde" #:limit 4)
|
||||
(cat "abcde" #:limit 4 #:limit-marker "*")
|
||||
(cat "abcde" #:limit 4 #:limit-marker "")
|
||||
(cat "The quick brown fox" #:limit 15 #:limit-marker "")
|
||||
(cat "The quick brown fox" #:limit 15 #:limit-marker "...")
|
||||
]
|
||||
|
||||
If @racket[_s] is shorter than @racket[pad-to], it is padded to at
|
||||
least @racket[pad-to] characters. If @racket[align] is
|
||||
@racket['left], then only right padding is added; if @racket[align]
|
||||
is @racket['right], then only left padding is added; and if
|
||||
@racket[align] is @racket['center], then roughly equal amounts of
|
||||
left padding and right padding are added.
|
||||
|
||||
Padding is specified as a non-empty string. Left padding consists of
|
||||
@racket[left-padding] repeated in its entirety as many times as
|
||||
possible followed by a @emph{prefix} of @racket[left-padding] to fill
|
||||
the remaining space. In contrast, right padding consists of a
|
||||
@emph{suffix} of @racket[right-padding] followed by a number of copies
|
||||
of @racket[right-padding] in its entirety. Thus left padding starts
|
||||
with the start of @racket[left-padding] and right padding ends with
|
||||
the end of @racket[right-padding].
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(cat "apple" #:pad-to 20 #:align 'left)
|
||||
(cat "pear" #:pad-to 20 #:align 'left #:right-padding " .")
|
||||
(cat "plum" #:pad-to 20 #:align 'right #:left-padding ". ")
|
||||
(cat "orange" #:pad-to 20 #:align 'center
|
||||
#:left-padding "- " #:right-padding " -")
|
||||
]
|
||||
|
||||
Use @racket[width] to set both @racket[limit] and @racket[pad-to]
|
||||
simultaneously, ensuring that the resulting string is exactly
|
||||
@racket[width] characters long:
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(cat "terse" #:width 6)
|
||||
(cat "loquacious" #:width 6)
|
||||
]
|
||||
}
|
||||
|
||||
@;{----------------------------------------}
|
||||
|
||||
@defproc[(catp [v any/c]
|
||||
[#:width width (or/c exact-nonnegative-integer? #f) #f]
|
||||
[#:limit limit (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
|
||||
[#:limit-marker limit-marker string? "..."]
|
||||
[#:pad-to pad-to exact-nonnegative-integer? (or width 0)]
|
||||
[#:align align (or/c 'left 'center 'right) 'left]
|
||||
[#:padding padding non-empty-string? " "]
|
||||
[#:left-padding left-padding non-empty-string? padding]
|
||||
[#:right-padding right-padding non-empty-string? padding])
|
||||
string?]{
|
||||
|
||||
Like @racket[cat], but converts a single @racket[v] to a string in
|
||||
@racket[print] mode---that is, like @racket[(format "~v" v)].
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catp "north")
|
||||
(catp 'south)
|
||||
(catp #"east")
|
||||
(catp #\w)
|
||||
(catp (list "red" 'green #"blue"))
|
||||
]
|
||||
|
||||
Use @racket[catp] to produce text that talks about Racket values.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(let ([nums (for/list ([i 10]) i)])
|
||||
(cat "The even numbers in " (catp nums)
|
||||
" are " (catp (filter even? nums)) "."))
|
||||
]
|
||||
}
|
||||
|
||||
@;{----------------------------------------}
|
||||
|
||||
@defproc[(catw [v any/c]
|
||||
[#:width width (or/c exact-nonnegative-integer? #f) #f]
|
||||
[#:limit limit (or/c exact-nonnegative-integer? +inf.0) (or width +inf.0)]
|
||||
[#:limit-marker limit-marker string? "..."]
|
||||
[#:pad-to pad-to exact-nonnegative-integer? (or width 0)]
|
||||
[#:align align (or/c 'left 'center 'right) 'left]
|
||||
[#:padding padding non-empty-string? " "]
|
||||
[#:left-padding left-padding non-empty-string? padding]
|
||||
[#:right-padding right-padding non-empty-string? padding])
|
||||
string?]{
|
||||
|
||||
Like @racket[cat], but converts a single @racket[v] to a string in
|
||||
@racket[write] mode---that is, like @racket[(format "~s" v)].
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catw "north")
|
||||
(catw 'south)
|
||||
(catw #"east")
|
||||
(catw #\w)
|
||||
(catw (list "red" 'green #"blue"))
|
||||
]
|
||||
}
|
||||
|
||||
@;{----------------------------------------}
|
||||
|
||||
@defproc[(catn [x rational?]
|
||||
[#:sign sign
|
||||
(or/c #f '+ '++ 'parens
|
||||
(let ([ind (or/c string? (list/c string? string?))])
|
||||
(list/c ind ind ind)))
|
||||
#f]
|
||||
[#:base base
|
||||
(or/c (integer-in 2 36) (list/c 'up (integer-in 2 36)))
|
||||
10]
|
||||
[#:precision precision
|
||||
(or/c exact-nonnegative-integer?
|
||||
(list/c '= exact-nonnegative-integer?))
|
||||
3]
|
||||
[#:pos/exp-range
|
||||
pos/exp-range
|
||||
(list/c (or/c exact-integer? +inf.0)
|
||||
(or/c exact-integer? -inf.0))
|
||||
(list -inf.0 +inf.0)]
|
||||
[#:exp-precision exp-precision
|
||||
(or/c exact-nonnegative-integer?
|
||||
(list/c '= exact-nonnegative-integer?))
|
||||
5]
|
||||
[#:exp-format-exponent exp-format-exponent
|
||||
(or/c #f string? (-> exact-integer? string?))
|
||||
#f]
|
||||
[#:pad-digits-to pad-digits-to exact-positive-integer? 1]
|
||||
[#:digits-padding digits-padding non-empty-string? " "])
|
||||
string?]{
|
||||
|
||||
Converts the rational number @racket[x] to a string in either
|
||||
positional or exponential notation. The exactness or inexactness of
|
||||
@racket[x] does not affect its formatting.
|
||||
|
||||
Numbers whose order of magnitude (with respect to @racket[base]) fall
|
||||
strictly within @racket[pos/exp-range] are formatted using positional
|
||||
notation. More precisely, if the following condition holds:
|
||||
|
||||
@racketblock[(or (zero? x)
|
||||
(< (expt base (car pos/exp-range))
|
||||
(abs x)
|
||||
(expt base (cadr pos/exp-range))))]
|
||||
|
||||
then the result is equivalent to
|
||||
|
||||
@racketblock[(catnp x
|
||||
#:sign sign-mode
|
||||
#:base base
|
||||
#:precision precision
|
||||
#:pad-digits-to pad-digits-to
|
||||
#:digits-padding digits-padding)]
|
||||
|
||||
Otherwise, the number is formatted in exponential notation, and the
|
||||
result is equivalent to
|
||||
|
||||
@racketblock[(catne x
|
||||
#:sign sign-mode
|
||||
#:base base
|
||||
#:precision exp-precision
|
||||
#:format-exponent exp-format-exponent
|
||||
#:pad-digits-to pad-digits-to
|
||||
#:digits-padding digits-padding)]
|
||||
|
||||
@examples[#:eval the-eval
|
||||
(catn 999 #:pos/exp-range '(0 3))
|
||||
(catn 1000 #:pos/exp-range '(0 3))
|
||||
(catn 0.9876 #:pos/exp-range '(0 3))
|
||||
]
|
||||
|
||||
Note that the default value of @racket[pos/exp-range] ensures that
|
||||
positional notation will be used for any rational @racket[x].
|
||||
}
|
||||
|
||||
|
||||
@defproc[(catnp [x rational?]
|
||||
[#:sign sign
|
||||
(or/c #f '+ '++ 'parens
|
||||
(let ([ind (or/c string? (list/c string? string?))])
|
||||
(list/c ind ind ind)))
|
||||
#f]
|
||||
[#:base base
|
||||
(or/c (integer-in 2 36) (list/c 'up (integer-in 2 36)))
|
||||
10]
|
||||
[#:precision precision
|
||||
(or/c exact-nonnegative-integer?
|
||||
(list/c '= exact-nonnegative-integer?))
|
||||
3]
|
||||
[#:pad-digits-to pad-digits-to exact-positive-integer? 1]
|
||||
[#:digits-padding digits-padding non-empty-string? " "])
|
||||
string?]{
|
||||
|
||||
Formats the rational number @racket[x] using positional notation according to
|
||||
the following arguments:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{@racket[precision] controls the number of digits after the decimal point
|
||||
(or more accurately, the
|
||||
@hyperlink["http://en.wikipedia.org/wiki/Radix_point"]{radix point}). If
|
||||
@racket[precision] is a natural number, then up to @racket[precision] digits are
|
||||
displayed, but trailing zeroes are dropped, and if all digits after the decimal
|
||||
point are dropped the decimal point is also dropped. If @racket[precision] is
|
||||
@racket[(list '= _digits)], then exactly @racket[_digits] digits after the
|
||||
decimal point are used, and the decimal point is never dropped.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catnp pi)
|
||||
(catnp pi #:precision 4)
|
||||
(catnp pi #:precision 0)
|
||||
(catnp 1.5 #:precision 4)
|
||||
(catnp 1.5 #:precision '(= 4))
|
||||
(catnp 50 #:precision 2)
|
||||
(catnp 50 #:precision '(= 2))
|
||||
(catnp 50 #:precision '(= 0))
|
||||
]}
|
||||
|
||||
@item{@racket[pad-digits-to]: if @racket[x] would normally be printed
|
||||
with fewer than @racket[pad-digits-to] digits (including the decimal
|
||||
point but not including the sign indicator), the output is left-padded
|
||||
using @racket[digits-padding].
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catnp 17)
|
||||
(catnp 17 #:pad-digits-to 4)
|
||||
(catnp -42 #:pad-digits-to 4)
|
||||
(catnp 1.5 #:pad-digits-to 4)
|
||||
(catnp 1.5 #:precision 4 #:pad-digits-to 10)
|
||||
(catnp 1.5 #:precision '(= 4) #:pad-digits-to 10)
|
||||
]}
|
||||
|
||||
@item{@racket[digits-padding] specifies the string used to pad the
|
||||
number to at least @racket[pad-digits-to] characters (not including the
|
||||
sign indicator). The padding is placed between the sign and the normal
|
||||
digits of @racket[x].
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catnp 17 #:pad-digits-to 4 #:digits-padding "0")
|
||||
(catnp -42 #:pad-digits-to 4 #:digits-padding "0")
|
||||
]}
|
||||
|
||||
@item{@racket[sign] controls how the sign of the number is
|
||||
indicated.
|
||||
@itemlist[
|
||||
|
||||
@item{If @racket[sign] is @racket[#f] (the default), no sign output is
|
||||
generated if @racket[x] is either positive or zero, and a minus sign is
|
||||
prefixed if @racket[x] is negative.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(for/list ([x '(17 0 -42)]) (catnp x))
|
||||
]}
|
||||
|
||||
@item{If @racket[sign] is @racket['+], no sign output is generated if
|
||||
@racket[x] is zero, a plus sign is prefixed if @racket[x] is positive, and a
|
||||
minus sign is prefixed if @racket[x] is negative.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(for/list ([x '(17 0 -42)]) (catnp x #:sign '+))
|
||||
]}
|
||||
|
||||
@item{If @racket[sign] is @racket['++], a plus sign is prefixed if @racket[x]
|
||||
is zero or positive, and a minus sign is prefixed if @racket[x] is negative.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(for/list ([x '(17 0 -42)]) (catnp x #:sign '++))
|
||||
]}
|
||||
|
||||
@item{If @racket[sign] is @racket['parens], no sign output is generated if
|
||||
@racket[x] is zero or positive, and the number is enclosed in parentheses if
|
||||
@racket[x] is negative.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(for/list ([x '(17 0 -42)]) (catnp x #:sign 'parens))
|
||||
]}
|
||||
|
||||
@item{If @racket[sign] is @racket[(list _pos-ind _zero-ind _neg-ind)], then
|
||||
@racket[_pos-ind], @racket[_zero-ind], and @racket[_neg-ind] are used to
|
||||
indicate positive, zero, and negative numbers, respectively. Each indicator is
|
||||
either a string to be used as a prefix or a list containing two strings: a
|
||||
prefix and a suffix.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(let ([sign-table '(("" " up") "an even " ("" " down"))])
|
||||
(for/list ([x '(17 0 -42)]) (catnp x #:sign sign-table)))
|
||||
]
|
||||
|
||||
The default behavior is equivalent to @racket['("" "" "-")]; the
|
||||
@racket['parens] mode is equivalent to @racket['("" "" ("(" ")"))].
|
||||
}
|
||||
]}
|
||||
|
||||
@item{@racket[base] controls the base that @racket[x] is formatted in. If
|
||||
@racket[base] is a number greater than @racket[10], then lower-case letters are
|
||||
used. If @racket[base] is @racket[(list 'up _base*)] and @racket[_base*] is
|
||||
greater than @racket[10], then upper-case letters are used.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catnp 100 #:base 7)
|
||||
(catnp 4.5 #:base 2)
|
||||
(catnp 3735928559 #:base 16)
|
||||
(catnp 3735928559 #:base '(up 16))
|
||||
]}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@defproc[(catne [x rational?]
|
||||
[#:sign sign
|
||||
(or/c #f '+ '++ 'parens
|
||||
(let ([ind (or/c string? (list/c string? string?))])
|
||||
(list/c ind ind ind)))
|
||||
#f]
|
||||
[#:base base
|
||||
(or/c (integer-in 2 36) (list/c 'up (integer-in 2 36)))
|
||||
10]
|
||||
[#:precision precision
|
||||
(or/c exact-nonnegative-integer?
|
||||
(list/c '= exact-nonnegative-integer?))
|
||||
5]
|
||||
[#:format-exponent
|
||||
format-exponent
|
||||
(or/c #f string? (-> exact-integer? string?))
|
||||
#f]
|
||||
[#:pad-digits-to pad-digits-to exact-positive-integer? 1]
|
||||
[#:digits-padding digits-padding non-empty-string? " "])
|
||||
string?]{
|
||||
|
||||
Formats the rational number @racket[x] in exponential notation according to the
|
||||
following arguments:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{@racket[base], @racket[sign] are interpreted as in positional notation,
|
||||
described above, except that they apply only to the significand, not the
|
||||
exponent.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne -100 #:base 2)
|
||||
]}
|
||||
|
||||
@item{@racket[format-exponent] determines how the exponent is displayed.
|
||||
|
||||
If @racket[format-exponent] is a string, the exponent is displayed with an
|
||||
explicit sign (as with a @racket[sign-mode] of @racket['++]) and at least two
|
||||
digits, separated from the significand by the ``exponent marker''
|
||||
@racket[format-exponent]:
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne 1234 #:format-exponent "E")
|
||||
]
|
||||
|
||||
If @racket[format-exponent] is @racket[#f], the ``exponent marker'' is
|
||||
@racket["e"] if @racket[base] is @racket[10] and a string involving
|
||||
@racket[base] otherwise:
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne 1234)
|
||||
(catne 1234 #:base 8)
|
||||
]
|
||||
|
||||
If @racket[format-exponent] is a procedure, it is applied to the exponent and
|
||||
the resulting string is appended to the significand:
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne 1234 #:format-exponent (lambda (e) (format "E~a" e)))
|
||||
]}
|
||||
|
||||
@item{@racket[precision] determines how many digits after the radix point the
|
||||
significand contains. Like the @racket[precision] argument of @racket[catnp],
|
||||
the form @racket[(list '= _digits)] causes trailing zeroes to be retained.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne 12345 #:precision 3)
|
||||
(catne 12345 #:precision 2)
|
||||
(catne 10000 #:precision 2)
|
||||
(catne 10000 #:precision '(= 2))
|
||||
]}
|
||||
|
||||
@item{@racket[pad-digits-to] and @racket[digits-padding] are interpreted as in
|
||||
positional notation.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(catne 12345 #:pad-digits-to 12 #:digits-padding " ")
|
||||
]}
|
||||
|
||||
]
|
||||
|
||||
@;{
|
||||
Note that unlike @racket[string->number] (and thus @racket[cat]), @racket[catn]
|
||||
does not use exponential notation for large (or small) inexact numbers. Large
|
||||
numbers will be displayed with a large number of digits, many of which are not
|
||||
significant.
|
||||
|
||||
@interaction[#:eval the-eval
|
||||
(cat (expt 6.1 87))
|
||||
(catn (expt 6.1 87))
|
||||
(code:line (catn (+ (expt 6.1 87) 1000)) (code:comment "how many of these digits are significant?"))
|
||||
]}
|
||||
}
|
||||
|
||||
@(close-eval the-eval)
|
|
@ -77,7 +77,6 @@ Keep documentation and tests up to date.
|
|||
@include-section["../automata/scribblings/automata.scrbl"]
|
||||
@include-section["bytes.scrbl"]
|
||||
@include-section["contract.scrbl"]
|
||||
@include-section["cat.scrbl"]
|
||||
@include-section["wrapc.scrbl"]
|
||||
@include-section["debug.scrbl"]
|
||||
@include-section["define.scrbl"]
|
||||
|
|
Loading…
Reference in New Issue
Block a user