sources from planet 1.5

pull/1/head
Matthew Butterick 9 years ago
parent 4cc4d7096b
commit 668032cec6
  1. 202
      describe-test.rkt
  2. 870
      describe.rkt
  3. 461
      describe.scrbl
  4. 39
      float-test-bigfloat.rkt
  5. 26
      float-test-double.rkt
  6. 27
      float-test-extended.rkt
  7. 26
      float-test-single.rkt
  8. 15
      info.rkt
  9. 674
      license.txt

@ -0,0 +1,202 @@
#lang racket
;;; describe-test.rkt
;;; Copyright (c) 2009-2010 M. Douglas Williams
;;;
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;;
(require math/bigfloat
racket/mpair)
(require (planet williams/describe/describe))
;;; Booleans
(printf "~n--- Booleans ---~n")
(describe #t)
(describe #f)
;;; Numbers
(printf "~n--- Numbers ---~n")
(define (! n)
(if (= n 0)
1
(* n (! (sub1 n)))))
(describe +inf.0)
(describe -inf.0)
(describe +nan.0)
(describe 0)
(describe (! 10))
(describe (! 40))
(describe (- (! 40) (! 41)))
(describe (! 100))
(describe (/ (! 10) (add1 (! 11))))
(describe -1+3i)
(describe 0.0)
(describe 0.1e0)
(describe 0.1f0)
(describe 0.1t0)
(describe (* (! 10) 1.0))
(describe 6.0221313e23)
(describe 6.0221313f23)
(describe 6.0221313t23)
(describe (exact->inexact (! 40)))
(describe (sqrt 10))
(describe (sqrt -10))
(describe (+ (sqrt 10) (sqrt -10)))
(describe (bf 1/10))
(describe (bf "15e200000000"))
;;; Strings
(printf "~n--- Strings ---~n")
(describe "abc")
(describe (string #\1 #\2 #\3))
;;; Byte Strings
(printf "~n--- Byte Strings ---~n")
(describe #"abc")
(describe (bytes 48 49 50))
;;; Characters
(printf "~n--- Characters ---~n")
(describe #\a)
(describe #\A)
(describe #\0)
(describe #\()
;;; Symbols
(printf "~n--- Symbols ---~n")
(describe 'abc)
(describe '|(a + b)|)
(describe (gensym))
;;; Regular Expressions
(printf "~n--- Regular Expressions ---~n")
(describe #rx"Ap*le")
(describe #px"Ap*le")
;;; Byte Regular Expressions
(printf "~n--- Byte Regular Expressions ---~n")
(describe #rx#"Ap*le")
(describe #px#"Ap*le")
;;; Keywords
(printf "~n--- Keywords ---~n")
(describe '#:key)
;;; Lists and Pairs
(printf "~n--- Lists and Pairs ---~n")
(describe '(this is a proper list))
(describe '(this is an improper . list))
(describe (list '(this . is) '(also . a) '(proper . list)))
;;; Mutable Lists and Pairs
(printf "~n--- Mutable Lists and Pairs ---~n")
(describe (mlist 'this 'is 'a 'proper 'list))
(describe (mcons 'this (mcons 'is (mcons 'an (mcons 'improper 'list)))))
(describe (mlist '(this . is) '(also . a) '(proper . list)))
;;; Vectors
(printf "~n--- Vectors ---~n")
(describe #(1 2 3))
;;; Boxes
(printf "~n--- Boxes ---~n")
(describe (box 12))
(describe (box (box 'a)))
(describe (box (sqrt 10)))
;;; Weak Boxes
(printf "~n--- Weak Boxes ---~n")
(describe (make-weak-box 12))
(describe (make-weak-box (make-weak-box 'a)))
(describe (make-weak-box (sqrt 10)))
;;; Hashes
(printf "~n--- Hashes ---~n")
(describe #hash((a . 12) (b . 14) (c . 16)))
(describe #hasheq((a . a) (b . b) (c . c)))
(describe #hasheqv((a . #\a) (b . #\b) (c . #\c)))
(define ht (make-hash))
(hash-set! ht 'a 12)
(hash-set! ht 'b 14)
(hash-set! ht 'c 16)
(describe ht)
(define wht (make-weak-hash))
(hash-set! wht 'a 12)
(hash-set! wht 'b 14)
(hash-set! wht 'c 16)
(describe wht)
;;; Procedures
(printf "~n--- Procedures ---~n")
(describe car)
(describe open-output-file)
(describe current-input-port)
(describe (lambda (x) x))
;;; Ports
(printf "~n--- Ports ---~n")
(describe (current-input-port))
(describe (current-output-port))
;;; Void
(printf "~n--- Void ---~n")
(describe (void))
;;; EOF
(printf "~n--- EOF ---~n")
(describe eof)
;;; Paths
(printf "~n--- Paths ---~n")
(describe (string->path "C:\\Program-files\\PLT"))
(describe (string->path "../dir/file.ext"))
;;; Structures
(printf "~n--- Structures ---~n")
(define-struct transparent-struct (a b c) #:transparent)
(define ts-1 (make-transparent-struct 'a 'b 'c))
(describe ts-1)
;;; Other Named Things (I.E., Opaque Structures)
(printf "~n--- Other Named Things ---~n")
(define-struct opaque-struct (a b c))
(define os-1 (make-opaque-struct 'a 'b 'c))
(describe os-1)

@ -0,0 +1,870 @@
#lang racket
;;; describe.rkt
;;; Copyright (c) 2009-2010 M. Douglas Williams
;;;
;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.
;;;
;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
;;;
;;; -----------------------------------------------------------------------------
;;;
;;; This file provides four procedures: variant, integer->string, describe,
;;; and description.
;;;
;;; (variant x) -> symbol?
;;; x : any/c
;;; Returns a symbol identifying the type of any object.
;;; Examples:
;;; (variant (λ (x) x)) -> procedure
;;; (variant 1) -> fixnum-integer
;;; (variant (let/cc k k)) -> continuation
;;; (variant (let/ec k k)) -> escape-continuation
;;;
;;; (integer->string n) -> string?
;;; n : exact-integer?
;;; Returns a string with the name of the exact integer n. This works for
;;; integers whose magnitude is less than 10e102.
;;; Examples:
;;; >(integer->string 0)
;;; "zero"
;;; >(integer->string (expt 2 16))
;;; "sixty-five thousand five hundred and thirty-six"
;;; > (integer->string (expt 10 100))
;;; "ten duotrigillion"
;;; > (integer->string (expt 10 150))
;;; "at least 10^102"
;;;
;;; (describe x) -> void?
;;; x : any/c
;;; Prints a description of x to the current output port.
;;; Examples:
;;; >(describe (sqrt 10))
;;; 3.1622776601683795 is an inexact positive real number
;;; >(describe (sqrt -10))
;;; 0+3.1622776601683795i is an inexact positive imaginary number
;;; >(describe #\a)
;;; #\a is the character whose code-point number is 97(#x61) and general category is 'll (letter, lowercase)
;;; >(describe '(this is a proper list))
;;; (this is a proper list) is a proper immutable list of length 5
;;; >(describe car)
;;; #<procedure:car> is a primitive procedure named car that accepts 1 argument and returns 1 result
;;;
;;; (description x) -> string?
;;; x : any/c
;;; Returns a string describing the object, x.
;;;
;;; -----------------------------------------------------------------------------
;;;
;;; Version Date Description
;;; 1.0.0 11/10/09 Initial Release to PLaneT (MDW)
;;; 2.0.0 10/27/10 Updated to Racket. (MDW)
;;; 2.0.1 08/26/13 Added exact decimal value for floats. (MDW)
;;; 2.0.1 09/26/13 Added bigfloat support to float->string. (MDW)
(require math/bigfloat
racket/extflonum
racket/mpair)
;;; (variant x) -> symbol
;;; x : any/c
;;; Returns a symbol identifying the type of any object. This is from a post on
;;; The PLT Scheme mailing list from Robby Findler. The following is a short
;;; explanation of its origin:
;;; I'm not sure about always, but at some point a while ago, Matthew
;;; decided that all values are structs (in the sense that you could have
;;; implemented everything with structs and scope, etc even if some of
;;; them are implemented in C) and adapted the primitives to make them
;;; behave accordingly.
;;; Examples:
;;; (variant (λ (x) x)) -> procedure
;;; (variant 1) -> fixnum-integer
;;; (variant (let/cc k k)) -> continuation
;;; (variant (let/ec k k)) -> escape-continuation
(define (variant x)
(string->symbol
(regexp-replace #rx"^struct:"
(symbol->string (vector-ref (struct->vector x) 0))
"")))
;;; (imaginary? z) -> boolean?
;;; z : any/c
;;; Returns #t if z is an imaginary number. An imaginary number is a complex
;;; number whose real part is exactly zero and whose imaginary part is not
;;; zero.
(define (imaginary? z)
(and (complex? z)
(let ((zr (real-part z)))
(and (exact? zr) (zero? zr)))
;(let ((zi (imag-part z)))
; (not (and (exact? zi) (zero? zi))))
))
;;; (boolean-description bool) -> string?
;;; bool : boolean?
;;; Returns a string describing the boolean, bool.
(define (boolean-description bool)
(format "~s is a Boolean ~a"
bool (if bool "true" "false")))
;;; small-integer-names : (vectorof string?)
;;; A vector of the names of the integers less than 20.
(define small-integer-names
#("zero" ; not used
"one"
"two"
"three"
"four"
"five"
"six"
"seven"
"eight"
"nine"
"ten"
"eleven"
"twelve"
"thirteen"
"fourteen"
"fifteen"
"sixteen"
"seventeen"
"eighteen"
"nineteen"))
;;; (integer-0-19->string n) -> string?
;;; n : (and/c exact? (integer-in 0 19))
;;; Returns a string with the name of the number n, which must be between
;;; 0 and 19 (i.e., less than 20).
(define (integer-0-19->string n)
(vector-ref small-integer-names n))
;;; decade-names : (vectorof string?)
;;; The names of the multiples of ten that are less than 100.
(define decade-names
#("zero" ; not used
"ten"
"twenty"
"thirty"
"forty"
"fifty"
"sixty"
"seventy"
"eighty"
"ninety"))
;;; (integer-0-99->string n) -> string?
;;; n : (and/c exact? (integer-in 0 99))
;;; Returns a string with the name of the integer n, which must be between
;;; 0 and 99 (i.e., less than 100).
(define (integer-0-99->string n)
(if (< n 20)
(integer-0-19->string n)
(let-values (((q10 r10) (quotient/remainder n 10)))
(if (= r10 0)
(vector-ref decade-names q10)
(string-append (vector-ref decade-names q10)
"-"
(vector-ref small-integer-names r10))))))
;;; (integer-0-999->string n include-and?) -> string?
;;; n : (and/c exact? (integer-in 0 999))
;;; include-and? : boolean? = #f
;;; Returns a string with the name of the integer n, which must be between
;;; 0 and 999 (i.e., less than 1000). If include-and? is true, the British
;;; convention of including and after the hundreds is used.
(define (integer-0-999->string n (include-and? #f))
(if (< n 100)
(integer-0-99->string n)
(let-values (((q100 r100) (quotient/remainder n 100)))
(string-append (vector-ref small-integer-names q100)
" hundred"
(if (= r100 0)
""
(string-append (if include-and? " and " " ")
(integer-0-99->string r100)))))))
;;; thousands-names : (vectorof string?)
;;; The names of powers of a thousand up to 10^99, so they can be used for
;;; integers less than 10^102.
(define thousands-names
#("zero" ; not used
"thousand"
"million"
"billion"
"trillion"
"quadrillion"
"quintillion"
"sextillion"
"septillion"
"octillion"
"nonillion"
"decillion"
"undecillion"
"duodecillion"
"tredecillion"
"quattuordecillion"
"quindecillion"
"sexdecillion"
"septemdecillion"
"octdecillion"
"novemdecillion"
"vigintillion"
"unvigintillion"
"duovigintillion"
"tresvigintillion"
"quattuorvigintillion"
"quinquavigintillion"
"sesvigintillion"
"septenviginitillion"
"octovigintillion"
"novemvigintillion"
"trigintillion"
"untrigillion"
"duotrigillion"))
;;; max-integer->string : exact-positive-integer? = (expt 10 102)
;;; The limit for returning the name of an integer.
(define max-integer->string (expt 10 102))
;;; (integer->string n) -> string?
;;; n : exact-integer?
;;; Returns a string with the name of the exact integer n. This works for
;;; integers whose magnitude is less than 10e102.
(define (integer->string n)
(cond ((zero? n)
"zero")
((negative? n)
(string-append "minus " (integer->string (abs n))))
((< n 1000)
(integer-0-999->string n #t))
((< n max-integer->string)
(let/ec exit
(let loop ((str "")
(thousand-power 0)
(n n))
(if (= n 0)
(exit str)
(let-values (((q1000 r1000) (quotient/remainder n 1000)))
(loop (if (= thousand-power 0)
(if (= r1000 0)
""
(if (< r1000 20)
(string-append "and "
(integer-0-19->string r1000))
(integer-0-999->string r1000 #t)))
(if (= r1000 0)
str
(string-append (integer-0-999->string r1000)
" "
(vector-ref thousands-names thousand-power)
(if (> (string-length str) 0) " " "")
str)))
(+ thousand-power 1)
q1000))))))
(else
"at least 10^102")))
;;; (exact-number-description z) -=> string?
;;; z : (and/c number? exact?)
;;; Returns a string describing the exact number, z.
(define (exact-number-description z)
(cond ((fixnum? z)
(if (zero? z)
(format "~a is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) zero" z)
(if (byte? z)
(format "~s is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) ~a"
z (integer->string z))
(format "~s is an exact ~a integer fixnum ~a"
z (if (negative? z) "negative" "positive")
(integer->string z)))))
((and (integer? z) (< z max-integer->string))
(format "~s is an exact ~a integer ~a"
z (if (negative? z) "negative" "positive")
(integer->string z)))
((integer? z)
(format "~s is an exact ~a integer value whose absolute value is >= 10^102"
z (if (negative? z) "negative" "positive")))
((rational? z)
(format "~s is an exact ~a rational number with a numerator of ~a and a denominator of ~a"
z (if (negative? z) "negative" "positive")
(numerator z) (denominator z)))
((imaginary? z)
(format "~s is an exact ~a imaginary number"
z (if (negative? (imag-part z)) "negative" "positive")))
((complex? z)
(format "~s is an exact complex number whose real part is ~a and whose imaginary part is 0+~ai"
z (real-part z) (imag-part z)))
(else
(format "~s is an exact number" z))))
;;; (float->string x) -> string?
;;; x : (or/c flonum? single-flonum? extflonum? bigfloat?)
;;; Returns a string with the exact decimal representation of x. This is only
;;; guaranteed for floats - single, double, or extended precision, which are
;;; never repeating decimals.
(define (float->string x)
(define (int->string int)
(if (= int 0)
"0"
(let loop ((str "")
(n int))
(cond ((= n 0)
str)
(else
(define-values (q r) (quotient/remainder n 10))
(loop (string-append (number->string r) str) q))))))
(define (frac->string frac)
(if (= frac 0)
".0"
(let loop ((str ".")
(f frac))
(cond ((= f 0)
str)
(else
(define ten-f (* f 10))
(define ten-f-int (truncate ten-f))
(define ten-f-frac (- ten-f ten-f-int))
(loop (string-append str (number->string ten-f-int)) ten-f-frac))))))
;(define sign (sgn x))
;(define sign (if (extflonum? x)
; (cond ((extfl< x 0.0t0) -1.0)
; ((extfl> x 0.0t0) +1.0)
; (else 0.0))
; (sgn x)))
(define sign (cond ((bigfloat? x)
(cond ((bf< x 0.bf) -1.0)
((bf> x 0.bf) +1.0)
(else 0.0)))
((extflonum? x)
(cond ((extfl< x 0.0t0) -1.0)
((extfl> x 0.0t0) +1.0)
(else 0.0)))
(else
(sgn x))))
;(define exact-x (abs (inexact->exact x)))
;(define exact-x (if (extflonum? x)
; (abs (extfl->exact x))
; (abs (inexact->exact x))))
(define exact-x (cond ((bigfloat? x) (abs (bigfloat->rational x)))
((extflonum? x) (abs (extfl->exact x)))
(else (inexact->exact x))))
(define int (truncate exact-x))
(define frac (- exact-x int))
(string-append
(if (= sign -1) "-" "")
(int->string int)
(frac->string frac)))
;;; (inexact-number-description z) -> string?
;;; z : (and/c number? inexact?)
;;; Returns a string describing the inexact number, z.
(define (inexact-number-description z)
(cond ((integer? z)
(if (zero? z)
(format "~a is an inexact integer zero" z)
(format "~s is an inexact ~a integer whose exact decimal value is ~a"
z (if (negative? z) "negative" "positive")
(float->string z))))
((real? z)
(format "~s is an inexact ~a real number whose exact decimal value is ~a"
z (if (negative? z) "negative" "positive")
(float->string z)))
((imaginary? z)
(format "~s is an inexact ~a imaginary number whose exact decimal value is 0+~ai"
z (if (negative? (imag-part z)) "negative" "positive")
(float->string (imag-part z))))
((complex? z)
(format "~s is an inexact complex number whose real part ~a and whose imaginary part ~a"
z (description (real-part z))
(description (make-rectangular 0 (imag-part z)))))
(else
(format "~s is an inexact number whose exact decimal value is ~a"
z (float->string z)))))
;;; (number-description z) -> string?
;;; z : number?
;;; Returns a string describing the number, z. It handles infinities and
;;; not-a-number directly and dispatches to handle exact or inexact numbers.
(define (number-description z)
(cond ((eqv? z +inf.0)
(format "~s is positive infinity" z))
((eqv? z -inf.0)
(format "~s is negative infinity" z))
((eqv? z +nan.0)
(format "~s is not-a-number" z))
((exact? z)
(exact-number-description z))
((inexact? z)
(inexact-number-description z))
(else
(format "~s is a number" z))))
;;; (extflonum-description x) -> string
;;; x : extflonum?
;;; Returns a string describing the extended precision floating point number, x.
(define (extflonum-description x)
(cond ((eqv? x +inf.t)
(format "~s is positive infinity" x))
((eqv? x -inf.t)
(format "~s is negative infinity" x))
((eqv? x +nan.t)
(format "~s is not-a-number" x))
(else
(format "~s is an extended precision (80-bit) floating point number whose exact decimal value is ~a"
x (float->string x)))))
;;; (bigfloat-description x) -> string
;;; x : extflonum?
;;; Returns a string describing the big float, x.
(define (bigfloat-description x)
(cond ((eqv? x +inf.bf)
(format "~s is positive infinity" x))
((eqv? x -inf.bf)
(format "~s is negative infinity" x))
((eqv? x +nan.bf)
(format "~s is non-a-number" x))
(else
(format "~s is a ~a big float with ~a bits of precision"
x (if (bfnegative? x) "negative" "positive")
(bigfloat-precision x)))))
;;; (string-description str) -> string?
;;; str : string?
;;; Returns a string describing the string, str.
(define (string-description str)
(let ((len (string-length str)))
(if (= len 0)
(format "~s is an empty string" str)
(format "~s is ~a string of length ~a"
str (if (immutable? str) "an immutable" "a mutable") len))))
;;; (byte-string-description bstr) -> string?
;;; bstr : string?
;;; Returns a string describing the string, bstr.
(define (byte-string-description bstr)
(let ((len (bytes-length bstr)))
(if (= len 0)
(format "~s is an empty byte string" bstr)
(format "~s is ~a byte string of length ~a"
bstr (if (immutable? bstr) "an immutable" "a mutable") len))))
;;; general-category-alist : (list-of (cons/c symbol? string?))
;;; An association list mapping a Unicode general category (as returned by
;;; char-general-category) to a string describing it.
(define general-category-alist
'((lu . "letter, uppercase")
(ll . "letter, lowercase")
(lt . "letter, titlecase")
(lm . "letter, modifier")
(lo . "letter, other")
(mn . "mark, nonspacing")
(mc . "mark, space combining")
(me . "mark, enclosing")
(nd . "number, decimal digit")
(nl . "number, letter")
(no . "number, other")
(ps . "punctuation, open")
(pe . "punctuation, close")
(pi . "punctuation, initial quote")
(pf . "punctuation, final quote")
(pd . "punctuation, dash")
(pc . "punctuation, connector")
(po . "punctuation, other")
(sc . "symbol, currency")
(sm . "symbol, math")
(sk . "symbol, modifier")
(so . "symbol, other")
(zs . "separator, space")
(zp . "separator, paragraph")
(zl . "separator, line")
(cc . "other, control")
(cf . "other, format")
(cs . "other, surrogate")
(co . "other, private use")
(cn . "other, not assigned")))
;;; (general-category->string category) -> string?
;;; category : symbol?
;;; Returns a string with the definition of Unicode general category, category,
;;; or "unknown" is category is not known.
(define (general-category->string category)
(let ((category-assoc (assq category general-category-alist)))
(if category-assoc
(cdr category-assoc)
"unknown")))
;;; (character-description char) -> string?
;;; char : character?
;;; Returns a string describing the character, char.
(define (character-description char)
(let ((code-point (char->integer char))
(general-category (char-general-category char)))
(format "~s is a character whose code-point number is ~a(#x~x) and general category is '~a (~a)"
char code-point code-point
general-category (general-category->string general-category))))
;;; symbol-description sym) -> string?
;;; sym : symbol?
;;; Returns a string describing the symbol, sym.
(define (symbol-description sym)
(format "~s is ~a symbol"
sym (if (symbol-interned? sym) "an interned" "an uninterned")))
;;; (regexp-description regexp) -> string?
;;; regexp : regexp?
;;; Returns a string describinbg the regular expression, regexp.
(define (regexp-description regexp)
(format "~s is a regular expression in ~a format"
regexp (if (pregexp? regexp) "pregexp" "regexp")))
;;; (byte-regexp-description byte-regexp) -> string?
;;; byte-regexp : buteregexp?
;;; Returns a string describing the byte regular expression, byte-regexp.
(define (byte-regexp-description byte-regexp)
(format "~s is a byte regular expression in ~a format"
byte-regexp (if (byte-pregexp? byte-regexp) "pregexp" "regexp")))
;;; (keyword-description kw) -> string?
;;; kw : keyword?
;;; Returns a string describing the keyword, kw.
(define (keyword-description kw)
(format "~s is a keyword" kw))
;;; (list-description lst) -> string?
;;; lst : list?
;;; Returns a string describing the proper immutable list, lst.
(define (list-description lst)
(if (null? lst)
(format "~s is an empty list" lst)
(format "~s is a proper immutable list of length ~a"
lst (length lst))))
;;; (pair-desc pair) -> string?
;;; pair : pair?
;;; Returns a string describing the improper immutable list, pair. Any pair that
;;; is not a proper list is an improper list.
(define (pair-description pair)
(format "~a is an improper immutable list" pair))
;;; (mlist-description mlst) -> string?
;;; mlst : mlist?
;;; Returns a string describing the proper mutable list, mlst.
(define (mlist-description mlst)
(format "~s is a proper mutable list of length ~a"
mlst (mlength mlst)))
;;; (mpair-desc mpair) -> string?
;;; mpair : mpair?
;;; Returns a string describing the improper mutable list, mpair. Any mpair that
;;; is not a proper mlist is an improper mlist.
(define (mpair-description mpair)
(format "~a is an improper mutable list" mpair))
;;; (vector-description v) -> string?
;;; v : vector?
;;; Returns a string describing the vector, v.
(define (vector-description v)
(let ((len (vector-length v)))
(if (= len 0)
(format "~s is an empty vector" v)
(format "~s is ~a vector of length ~a"
v (if (immutable? v) "an immutable" "a mutable") len))))
;;; (box-description box) -> string?
;;; box : box?
;;; Returns a string describing the boxed value, box, and its contents.
(define (box-description box)
(format "~s is a box containing ~s, ~a"
box (unbox box) (description (unbox box))))
;;; (weak-box-description weak-box) -> string?
;;; weak-box : weak-box?
;;; Returns a string describing the weak-box value, weak-box, and its contents.
(define (weak-box-description weak-box)
(format "~s is a weak box containing ~s, ~a"
weak-box (weak-box-value weak-box) (description (weak-box-value weak-box))))
;;; (ephemeron-description eph) -> string?
;;; eph : box?
;;; Returns a string describing the ephemeron value, eph, and its contents.
(define (ephemeron-description eph)
(format "~s is an ephemeron containing ~s, ~a"
eph (ephemeron-value eph) (description (ephemeron-value eph))))
;;; (hash-description hash) -> string?
;;; hash : hash?
;;; Returns a string describing the hash table, hash.
(define (hash-description hash)
(if (= (hash-count hash) 0)
(let ((type (if (hash-weak? hash)
"an empty mutable hash table that holds its keys weakly"
(if (immutable? hash)
"an empty immutable hash table"
"a empty mutable hash table")))
(compare (if (hash-eq? hash)
"eq?"
(if (hash-eqv? hash)
"eqv?"
"equal?"))))
(format "~s is ~a and that uses ~a to compare keys"
hash type compare))
(let ((type (if (hash-weak? hash)
"a mutable hash table that holds its keys weakly"
(if (immutable? hash)
"an immutable hash table"
"a mutable hash table")))
(compare (if (hash-eq? hash)
"eq?"
(if (hash-eqv? hash)
"eqv?"
"equal?"))))
(format "~s is ~a and that uses ~a to compare keys~a"
hash type compare
(for/fold ((key-text ""))
(((key value) (in-hash hash)))
(string-append key-text
(format "~n ~s : ~s, ~a"
key value (description value))))))))
;;; (arity->string arity) -> string?
;;; arity : (or/c exact-nonnegative-integer?
;;; arity-at-least?
;;; (list-of (or/c exact-nonnegative-integer?
;;; arity-at-least?)))
;;; Returns a string describing the arity of a function as returned by
;;; procedure-arity.
(define (arity->string arity)
(cond ((integer? arity)
(number->string arity))
((arity-at-least? arity)
(format "at least ~a" (arity-at-least-value arity)))
(else
(let loop ((str "")
(tail arity))
(let ((arity (car tail)))
(if (null? (cdr tail))
(string-append str " or " (arity->string arity))
(loop (string-append str
(if (> (string-length str) 0) ", " "")
(arity->string arity))
(cdr tail))))))))
;;; (keyword-list->string kw-lst) -> string?
;;; kw-lst : (list-of keyword?)
;;; Returns a string with the keywords from the keyword list, kw-lst.
(define (keyword-list->string kw-lst)
(cond ((= (length kw-lst) 0)
"")
((= (length kw-lst) 1)
(string-append "#:" (keyword->string (car kw-lst))))
(else
(let/ec exit
(let loop ((str "")
(tail kw-lst))
(if (null? (cdr tail))
(exit (string-append str
" and "
"#:" (keyword->string (car tail))))
(loop (string-append str
(if (> (string-length str) 0) ", " "")
"#:" (keyword->string (car tail)))
(cdr tail))))))))
;;; (procedure-arguments->string proc) -> string?
;;; proc : procedure?
;;; Returns a string describing the arguments of the procedure, proc.
(define (procedure-arguments->string proc)
(let ((arity (procedure-arity proc)))
(let-values (((required accepted) (procedure-keywords proc)))
(format "accepts ~a ~a~a~a"
(arity->string arity) (if (eqv? arity 1) "argument" "arguments")
(if (null? required)
""
(format " with keyword ~a ~a"
(if (= (length required) 1) "argument" "arguments")
(keyword-list->string required)))
(if (null? accepted)
""
(format " plus optional keyword ~a ~a"
(if (= (length accepted) 1) "argument" "arguments")
(keyword-list->string accepted)))))))
;;; (primitive-results->string prim) -> string
;;; prim : primitive?
;;; Returns a string describing the results of the primitive procedure, prim.
(define (primitive-results->string prim)
(let ((arity (primitive-result-arity prim)))
(format "returns ~a ~a"
(arity->string arity) (if (eqv? arity 1) "result" "results"))))
;;; (procedure-description proc) -> string?
;;; proc : procedure?
;;; Returns a string describing the procedure, proc.
(define (procedure-description proc)
(cond ((primitive? proc)
(let ((result-arity (procedure-arity proc)))
(format "~s is a primitive procedure ~athat ~a and ~a"
proc
(let ((name (object-name proc)))
(if name
(string-append "named "
(symbol->string name)
" ")
""))
(procedure-arguments->string proc)
(primitive-results->string proc))))
((primitive-closure? proc)
(format "~s is a primitive closure ~athat ~a"
proc
(let ((name (object-name proc)))
(if name
(string-append "named "
(symbol->string name))
""))
(procedure-arguments->string proc)))
(else
(format "~s is a procedure ~athat ~a"
proc
(let ((name (object-name proc)))
(if name
(string-append "named "
(symbol->string name)
" ")
""))
(procedure-arguments->string proc)))))
;;; (port-description port) -> string?
;;; port : port?
;;; Returns a string describing the port, port.
(define (port-description port)
(let ((direction (if (input-port? port)
(if (output-port? port)
"input-output"
"input")
(if (output-port? port)
"output"
"unknown"))))
(format "~s is ~a ~a port"
port (if (port-closed? port) "a closed" "an open")
direction)))
(define (path-description path)
(let ((convention (path-convention-type path)))
(format "~s is ~a ~a ~a path"
path
(if (complete-path? path) "a complete," "an incomplete,")
(if (absolute-path? path)
"absolute"
(if (relative-path? path)
"relative"
"unknown"))
convention)))
;;; (structure-description struct) -> string
(define (structure-description struct)
(let ((name (object-name struct)))
(format "~s is a structure~a~a"
struct
(if name (format " of type ~a" name) "")
(for/fold ((str ""))
((field (in-vector (struct->vector struct)))
(i (in-naturals)))
(cond ((= i 0)
"")
((eq? field '...)
(string-append str (format "~n ...")))
(else
(string-append str (format "~n ~a : ~a, ~a"
i field (description field)))))))))
;;; (description x) -> string
;;; x : any/c
;;; Returns a string describing x.
(define (description x)
(cond ((boolean? x)
(boolean-description x))
((number? x)
(number-description x))
((extflonum? x)
(extflonum-description x))
((bigfloat? x)
(bigfloat-description x))
((string? x)
(string-description x))
((bytes? x)
(byte-string-description x))
((char? x)
(character-description x))
((symbol? x)
(symbol-description x))
((regexp? x)
(regexp-description x))
((byte-regexp? x)
(byte-regexp-description x))
((keyword? x)
(keyword-description x))
((list? x)
(list-description x))
((pair? x)
(pair-description x))
((mlist? x)
(mlist-description x))
((mpair? x)
(mpair-description x))
((vector? x)
(vector-description x))
((box? x)
(box-description x))
((weak-box? x)
(weak-box-description x))
((hash? x)
(hash-description x))
((procedure? x)
(procedure-description x))
((port? x)
(port-description x))
((void? x)
(format "~s is void" x))
((eof-object? x)
(format "~s is an eof object" x))
((path? x)
(path-description x))
((struct? x)
(structure-description x))
(else
(let ((type (variant x))
(name (object-name x)))
(if (and object-name
(not (eq? type name)))
(format "~s is an object of type ~a named ~a"
x type name)
(format "~s is an object of type ~a"
x (variant x)))))))
;;; (describe x) -> void?
;;; x : any/c
;;; Prints a description of x.
(define (describe x)
(printf "~a~n" (description x)))
;;; Module Contracts
(provide/contract
(variant
(-> any/c symbol?))
(integer->string
(-> exact-integer? string?))
(float->string
(-> (or/c flonum? single-flonum? extflonum? bigfloat?) string?))
(description
(-> any/c string?))
(describe
(-> any/c void?)))

@ -0,0 +1,461 @@
#lang scribble/doc
@(require scribble/manual
(planet williams/describe/describe)
(for-label
racket
(planet williams/describe/describe)))
@title[#:tag "describe"]{Describe}
M. Douglas Williams
@(author+email @tt{M. Douglas Williams} "doug@cognidrome.org")
This library provides functions to describe Racket objects. Currently, the following types of objects are described:
@itemize{
@item{Booleans}
@item{Numbers}
@item{Strings}
@item{Byte Strings}
@item{Characters}
@item{Symbols}
@item{Regular Expressions}
@item{Byte Regular Expressions}
@item{Keywords}
@item{Lists and Pairs}
@item{Mutable Lists and Pairs}
@item{Vectors}
@item{Boxes}
@item{Weak Boxes}
@item{Hash Tables}
@item{Procedures}
@item{Ports}
@item{Void}
@item{EOF}
@item{Path}
@item{Structures}
@item{Other Named Things}
@item{Other (Unnamed) Things}
}
The describe library is available from the PLaneT repository.
@defmodule[(planet williams/describe/describe)]
@table-of-contents[]
@section{Interface}
The describe library provides the following functions:
@defproc[(variant (x any/c)) symbol?]{
Returns a symbol identifying the type of @scheme[x]. This is from a post on the Racket mailing list from Robby Findler. The following is a short description of its origin:
... I'm not sure about always, but at some point a while ago, Matthew decided that all values are structs (in the sense that you could have implemented everything with structs and scope, etc even if some of them are implemented in C) and adapted the primitives to make them behave accordingly.}
Examples:
@scheme[(variant (λ (x) x))] -> procedure
@scheme[(variant 1)] -> fixnum-integer
@scheme[(variant (let/cc k k))] -> continuation
@scheme[(variant (let/ec k k))] -> escape-continuation
@defproc[(integer->string (n exact-integer?)) string?]{
Returns a string with the name of the exact integer @scheme[n]. This works for exact integers whose magnitudes are less than 10^102. For values whose magnitudes are greater than or equal to 10^102, the string "at least 10^102" (or "minus at least 10^102") is returned.}
Examples:
@scheme[(integer->string 0)] -> "zero"
@scheme[(integer->string (expt 2 16))] -> "sixty-five thousand five hundred and thirty-six"
@scheme[(integer->string (expt 10 100))] -> "ten duotrigillion"
@scheme[(integer->string (expt 10 150))] -> "at least 10^102"
@defproc[(float->string (x (or/c flonum? single-flonum? extflonum? bigfloat?))) string?]{
Returns a string with the exact decimal value of the floating-point number @scheme[x]. This works for single precision, double precision, extended precision, and big floating-point values. Note that internally @scheme[x] is converted to an exact rational number as part of converting to a string and the following warning from the Arbitrary-Precision Floating-Point Numbers (Bigfloats) section in the Math Library is important.
@bold{Be careful with exact conversions.} Bigfloats with large exponents may not fit in memory as integers or exact rationals. Worse, they might fit, but have all your RAM and swap space for lunch.
}
Examples:
@scheme[(float->string 0.0)] -> "0.0"
@scheme[(float->string 1.0)] -> "1.0"
@scheme[(float->string 0.1s0)] -> "0.100000001490116119384765625"
@scheme[(float->string 0.1)] -> "0.1000000000000000055511151231257827021181583404541015625"
@scheme[(float->string 0.1t0)] -> "0.1000000000000000000013552527156068805425093160010874271392822265625"
@scheme[(float->string (bf 1/10))] -> "0.10000000000000000000000000000000000000007346839692639296924804603357639035486366659729825547009429698164240107871592044830322265625"
@defproc[(describe (x any/c)) void?]{
Prints a description of @scheme[x] to the current output port.}
Examples:
@scheme[(describe (sqrt 10))] @linebreak[]
@schemefont{3.1622776601683795 is an inexact positive real number}
@scheme[(describe (sqrt -10))] @linebreak[]
@schemefont{0+3.1622776601683795i is an inexact positive imaginary number}
@scheme[(describe #\a)] @linebreak[]
@schemefont{#\a is the character whose code-point number is 97(#x61) and general category is 'll (letter, lowercase)}
@scheme[(describe '(this is a proper list))] @linebreak[]
@schemefont{(this is a proper list) is a proper immutable list of length 5}
@scheme[(describe car)] @linebreak[]
@schemefont{#<procedure:car> is a primitive procedure named car that accepts 1 argument and returns 1 result}
@defproc[(description (x any/c)) string?]{
Returns a string describing @scheme[x].}
@section{Example}
The following example demonstrates the varions function of the describe library.
@#reader scribble/comment-reader
(schememod
racket
(require scheme/mpair)
(require (planet williams/describe/describe))
;;; Booleans
(printf "~n--- Booleans ---~n")
(describe #t)
(describe #f)
;;; Numbers
(printf "~n--- Numbers ---~n")
(define (! n)
(if (= n 0)
1
(* n (! (sub1 n)))))
(describe +inf.0)
(describe -inf.0)
(describe +nan.0)
(describe 0)
(describe (! 10))
(describe (! 40))
(describe (- (! 40) (! 41)))
(describe (! 100))
(describe (/ (! 10) (add1 (! 11))))
(describe -1+3i)
(describe 0.0)
(describe 0.1e0)
(describe 0.1f0)
(describe 0.1t0)
(describe (* (! 10) 1.0))
(describe 6.0221313e23)
(describe 6.0221313f23)
(describe 6.0221313t23)
(describe (exact->inexact (! 40)))
(describe (sqrt 10))
(describe (sqrt -10))
(describe (+ (sqrt 10) (sqrt -10)))
(describe (bf 1/10))
(describe (bf "15e200000000"))
;;; Strings
(printf "~n--- Strings ---~n")
(describe "abc")
(describe (string #\1 #\2 #\3))
;;; Byte Strings
(printf "~n--- Byte Strings ---~n")
(describe #"abc")
(describe (bytes 48 49 50))
;;; Characters
(printf "~n--- Characters ---~n")
(describe #\a)
(describe #\A)
(describe #\0)
(describe #\()
;;; Symbols
(printf "~n--- Symbols ---~n")
(describe 'abc)
(describe '|(a + b)|)
(describe (gensym))
;;; Regular Expressions
(printf "~n--- Regular Expressions ---~n")
(describe #rx"Ap*le")
(describe #px"Ap*le")
;;; Byte Regular Expressions
(printf "~n--- Byte Regular Expressions ---~n")
(describe #rx#"Ap*le")
(describe #px#"Ap*le")
;;; Keywords
(printf "~n--- Keywords ---~n")
(describe '#:key)
;;; Lists and Pairs
(printf "~n--- Lists and Pairs ---~n")
(describe '(this is a proper list))
(describe '(this is an improper . list))
(describe (list '(this . is) '(also . a) '(proper . list)))
;;; Mutable Lists and Pairs
(printf "~n--- Mutable Lists and Pairs ---~n")
(describe (mlist 'this 'is 'a 'proper 'list))
(describe (mcons 'this (mcons 'is (mcons 'an (mcons 'improper 'list)))))
(describe (mlist '(this . is) '(also . a) '(proper . list)))
;;; Vectors
(printf "~n--- Vectors ---~n")
(describe #(1 2 3))
;;; Boxes
(printf "~n--- Boxes ---~n")
(describe (box 12))
(describe (box (box 'a)))
(describe (box (sqrt 10)))
;;; Weak Boxes
(printf "~n--- Weak Boxes ---~n")
(describe (make-weak-box 12))
(describe (make-weak-box (make-weak-box 'a)))
(describe (make-weak-box (sqrt 10)))
;;; Hashes
(printf "~n--- Hashes ---~n")
(describe #hash((a . 12) (b . 14) (c . 16)))
(describe #hasheq((a . a) (b . b) (c . c)))
(describe #hasheqv((a . #\a) (b . #\b) (c . #\c)))
(define ht (make-hash))
(hash-set! ht 'a 12)
(hash-set! ht 'b 14)
(hash-set! ht 'c 16)
(describe ht)
(define wht (make-weak-hash))
(hash-set! wht 'a 12)
(hash-set! wht 'b 14)
(hash-set! wht 'c 16)
(describe wht)
;;; Procedures
(printf "~n--- Procedures ---~n")
(describe car)
(describe open-output-file)
(describe current-input-port)
(describe (lambda (x) x))
;;; Ports
(printf "~n--- Ports ---~n")
(describe (current-input-port))
(describe (current-output-port))
;;; Void
(printf "~n--- Void ---~n")
(describe (void))
;;; EOF
(printf "~n--- EOF ---~n")
(describe eof)
;;; Paths
(printf "~n--- Paths ---~n")
(describe (string->path "C:\\Program-files\\PLT"))
(describe (string->path "../dir/file.ext"))
;;; Structures
(printf "~n--- Structures ---~n")
(define-struct transparent-struct (a b c) #:transparent)
(define ts-1 (make-transparent-struct 'a 'b 'c))
(describe ts-1)
;;; Other Named Things (I.E., Opaque Structures)
(printf "~n--- Other Named Things ---~n")
(define-struct opaque-struct (a b c))
(define os-1 (make-opaque-struct 'a 'b 'c))
(describe os-1)
)
Produces the following output.
@verbatim{
--- Booleans ---
#t is a Boolean true
#f is a Boolean false
--- Numbers ---
+inf.0 is positive infinity
-inf.0 is negative infinity
+nan.0 is not-a-number
0 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) zero
3628800 is an exact positive integer fixnum three million six hundred twenty-eight thousand eight hundred
815915283247897734345611269596115894272000000000 is an exact positive integer eight hundred fifteen quattuordecillion nine hundred fifteen tredecillion two hundred eighty-three duodecillion two hundred forty-seven undecillion eight hundred ninety-seven decillion seven hundred thirty-four nonillion three hundred forty-five octillion six hundred eleven septillion two hundred sixty-nine sextillion five hundred ninety-six quintillion one hundred fifteen quadrillion eight hundred ninety-four trillion two hundred seventy-two billion
-32636611329915909373824450783844635770880000000000 is an exact negative integer minus thirty-two quindecillion six hundred thirty-six quattuordecillion six hundred eleven tredecillion three hundred twenty-nine duodecillion nine hundred fifteen undecillion nine hundred nine decillion three hundred seventy-three nonillion eight hundred twenty-four octillion four hundred fifty septillion seven hundred eighty-three sextillion eight hundred forty-four quintillion six hundred thirty-five quadrillion seven hundred seventy trillion eight hundred eighty billion
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 is an exact positive integer value whose absolute value is >= 10^102
3628800/39916801 is an exact positive rational number with a numerator of 3628800 and a denominator of 39916801
-1+3i is an exact complex number whose real part is -1 and whose imaginary part is 0+3i
0.0 is an inexact integer zero
0.1 is an inexact positive real number whose exact decimal value is .1000000000000000055511151231257827021181583404541015625
0.1f0 is an inexact positive real number whose exact decimal value is .100000001490116119384765625
0.1t0 is an extended precision (80-bit) floating point number whose exact decimal value is .1000000000000000000013552527156068805425093160010874271392822265625
3628800.0 is an inexact positive integer whose exact decimal value is 3628800.
6.0221313e+023 is an inexact positive integer whose exact decimal value is 602213130000000012517376.
6.0221313f+023 is an inexact positive integer whose exact decimal value is 602213127606262401335296.
6.0221313t+023 is an extended precision (80-bit) floating point number whose exact decimal value is 602213130000000000000000.
8.159152832478977e+047 is an inexact positive integer whose exact decimal value is 815915283247897683795548521301193790359984930816.
3.1622776601683795 is an inexact positive real number whose exact decimal value is 3.162277660168379522787063251598738133907318115234375
0+3.1622776601683795i is an inexact positive imaginary number whose exact decimal value is 0+3.162277660168379522787063251598738133907318115234375i
3.1622776601683795+3.1622776601683795i is an inexact complex number whose real part 3.1622776601683795 is an inexact positive real number whose exact decimal value is 3.162277660168379522787063251598738133907318115234375 and whose imaginary part 0+3.1622776601683795i is an inexact positive imaginary number whose exact decimal value is 0+3.162277660168379522787063251598738133907318115234375i
(bf #e0.1000000000000000000000000000000000000001) is a positive big float with 128 bits of precision
(bf "1.499999999999999999999999999999999999998e200000001") is a positive big float with 128 bits of precision
--- Strings ---
"abc" is an immutable string of length 3
"123" is a mutable string of length 3
--- Byte Strings ---
#"abc" is an immutable byte string of length 3
#"012" is a mutable byte string of length 3
--- Characters ---
#\a is a character whose code-point number is 97(#x61) and general category is 'll (letter, lowercase)
#\A is a character whose code-point number is 65(#x41) and general category is 'lu (letter, uppercase)
#\0 is a character whose code-point number is 48(#x30) and general category is 'nd (number, decimal digit)
#\( is a character whose code-point number is 40(#x28) and general category is 'ps (punctuation, open)
--- Symbols ---
abc is an interned symbol
|(a + b)| is an interned symbol
g1454 is an uninterned symbol
--- Regular Expressions ---
#rx"Ap*le" is a regular expression in regexp format
#px"Ap*le" is a regular expression in pregexp format
--- Byte Regular Expressions ---
#rx#"Ap*le" is a byte regular expression in regexp format
#px#"Ap*le" is a byte regular expression in pregexp format
--- Keywords ---
#:key is a keyword
--- Lists and Pairs ---
(this is a proper list) is a proper immutable list of length 5
(this is an improper . list) is an improper immutable list
((this . is) (also . a) (proper . list)) is a proper immutable list of length 3
--- Mutable Lists and Pairs ---
{this is a proper list} is a proper mutable list of length 5
{this is an improper . list} is an improper mutable list
{(this . is) (also . a) (proper . list)} is a proper mutable list of length 3
--- Vectors ---
#(1 2 3) is an immutable vector of length 3
--- Boxes ---
#&12 is a box containing 12, 12 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) twelve
#&#&a is a box containing #&a, #&a is a box containing a, a is an interned symbol
#&3.1622776601683795 is a box containing 3.1622776601683795, 3.1622776601683795 is an inexact positive real number whose exact decimal value is 3.162277660168379522787063251598738133907318115234375
--- Weak Boxes ---
#<weak-box> is a weak box containing 12, 12 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) twelve
#<weak-box> is a weak box containing #<weak-box>, #<weak-box> is a weak box containing a, a is an interned symbol
#<weak-box> is a weak box containing 3.1622776601683795, 3.1622776601683795 is an inexact positive real number whose exact decimal value is 3.162277660168379522787063251598738133907318115234375
--- Hashes ---
#hash((a . 12) (b . 14) (c . 16)) is an immutable hash table and that uses equal? to compare keys
a : 12, 12 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) twelve
b : 14, 14 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) fourteen
c : 16, 16 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) sixteen
#hasheq((a . a) (b . b) (c . c)) is an immutable hash table and that uses eq? to compare keys
a : a, a is an interned symbol
b : b, b is an interned symbol
c : c, c is an interned symbol
#hasheqv((a . #\a) (b . #\b) (c . #\c)) is an immutable hash table and that uses eqv? to compare keys
a : #\a, #\a is a character whose code-point number is 97(#x61) and general category is 'll (letter, lowercase)
b : #\b, #\b is a character whose code-point number is 98(#x62) and general category is 'll (letter, lowercase)
c : #\c, #\c is a character whose code-point number is 99(#x63) and general category is 'll (letter, lowercase)
#hash((c . 16) (a . 12) (b . 14)) is a mutable hash table and that uses equal? to compare keys
c : 16, 16 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) sixteen
a : 12, 12 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) twelve
b : 14, 14 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) fourteen
#<hash> is a mutable hash table that holds its keys weakly and that uses equal? to compare keys
c : 16, 16 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) sixteen
a : 12, 12 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) twelve
b : 14, 14 is a byte (i.e., an exact positive integer fixnum between 0 and 255 inclusive) fourteen
--- Procedures ---
#<procedure:car> is a primitive procedure named car that accepts 1 argument and returns 1 result
#<procedure:open-output-file> is a procedure named open-output-file that accepts 1 argument plus optional keyword arguments #:exists and #:mode
#<procedure:current-input-port> is a primitive procedure named current-input-port that accepts 0 or 1 arguments and returns 1 result
#<procedure:...escribe-test.rkt:156:10> is a procedure named ...escribe-test.rkt:156:10 that accepts 1 argument
--- Ports ---
#<input-port:unsaved-editor326> is an open input port