You are looking at historical revision 26928 of this page. It may differ significantly from its current revision.

FOX

Author

Joo ChurlSoo

Changes

The optional arguments of the original CAT procedure were divided into three groups; arguments only for the number type of <object>, arguments for all types except the number type of <object>, and arguments for all types of <object>. This complexity can make users confused. Those of this revised one are divided into two groups; arguments only for the number type of <object> and arguments for all types of <object>. This simplicity also makes <writer> to be able to substitute for <converter>. The <precision> actually serves as ~G of Common Lisp's FORMAT and %G of C's PRINTF. The <point> of this revised one, an additional optional argument, serves as ~F or ~E of Common Lisp's FORMAT and %F or %E of C's PRINTF. This revised CAT procedure, FOX is for speed up of non-number type of object. For the purpose, the optional arguments only for the number type of object integrate into a list type argument, <merge>.

Additional extensions:

1. All optional arguments can be applied to the number type of <object>.

2. The default value of <writer> is DISPLAY procedure.

3. The <width> is an integer, and the <precision> is a non-negative exact integer.

4. The new optional arguments, <point> ('fixed or 'float), <pre-string>, and <post-string> are added.

5. The <take> is changed from a list to a pair, and its elements are exact integers, strings, or procedures.

6. The <separator> is changed from a list to a vector, and the second element of <separator> is a non-zero exact integer.

7. Infinities and nans of R6RS are supported.

8. The <pipe> is integrated into the <take>.

9. The <converter> is integrated into the <writer>.

Abstract

This introduces the FOX procedure that takes one object as the first argument and accepts a variable number of optional arguments, and returns a string.

Rationale

It is difficult to gain a complete consensus for the design of a generic formatting procedure that performs a variety of functions provided in C's PRINTF and Common lisp's FORMAT. One of such ways would be to devise a free non-sequent method that easily handles optional arguments, in contrast to the conventional fixed sequent method, in order to obtain a handy optional and functional interface.

Specification

[procedure] (fox <object> [<pre-string>] [<port>] [<width>] [<char>] [<writer>] [<merge>] [<take>] [<separator>] [<post-string>] ...)

<merge> --> ([<precision>] [<point>] [<radix>] [<sign>] [<exactness>])

The <merge> is a list whose elements are <precision>, <point>, <radix>, <sign>, and <exactness>. The <precision> <point> <radix> <sign> <exactness> are effective only for the number type of <object>. Except <string>s, the order of all other optional arguments does not matter. When there is a <string> or <string>s without the other optional arguments, the <string> or <string>s are <post-string>. The FOX process the optional arguments in the following order; <writer>, <exactness>, <point>, <precision>, <radix>, <separator>, <sign>, <take>, <width>, <char>, <string>, <port>.

1. The <object> is any Scheme object.

2. The <width> is an integer whose absolute value specifies the width of the resulting string. When the resulting string has fewer characters than the absolute value of <width>, it is placed rightmost with the rest being padded with <char>s, if <width> is positive, or it is placed leftmost with the rest being padded with <char>s, if <width> is negative, or it is placed in the center (near to right in case of positive <width>, or near to left in case of negative <width>) with the rest being padded with <char>s, if <width> is an inexact integer. On the other hand, when the resulting string has more characters than the absolute value of <width>, lthe <width> is ignored. The default value is 0.

3. The <writer> is a procedure of two arguments; <object> and a string port. It writes <object> to the string port. The default value is DISPLAY procedure. If you want any objects to be displayed in your own way, you have to define your own <writer>. Otherwise, they are displayed simply in their evaluated forms. When <writer> except DISPLAY and WRITE procedures is used, the optional arguments that are effective only for the number type of <object> become ineffective.

  

4. The <port> is an output port or a boolean. If an output port is specified, the resulting string is output into the port. If <port> is #t, the output port is current output port. If <port> is #f, the resulting string is returned. The default value is #f.

5. The <char> is a padding character. The default value is #\space.

6. The <take> is a pair whose car and cdr values are exact integers or strings or procedures; m and n, and the absolute values of m and n are M and N, respectively. First, When the car element is an exact integer, the resulting string takes from the left m-characters, if it is positive, or all the characters but M-characters, if non-positive. When the car element is a string, the string is prefixed. When the car element is a procedure, the procedure takes a string argument and returns a string as a pipe. Second, When the cdr element is an exact integer, the resulting string takes from the right n-characters of the string that is processed by the car element, if it is positive, or all the characters but N-characters, if non-positive. When the cdr element is a string, the string is postfixed to the string that is processed by the car element. When the cdr element is a procedure, the procedure takes the string processed by the car element as an argument and returns a string.

  

7. The <separator> is a vector whose first element is a string serving as a separator and second element is a non-zero exact integer; n, and the absolute value of n is N. The resulting string is separated in every N-characters of the resulting string from right end, if n is positive, or from left end, if n is negative. Even if n is a negative integer, its absolute value is used for the number type of <object>. When the integer is omitted, the <separator> is effective only for the number type of <object> and its default value is 3.

8. The <point> is a symbol: fixed or float. Each returns a string of decimal fraction or exponential representation.

9. The <precision> is a non-negative exact integer that specifies the number of decimal digits after a decimal point.

10. The <radix> is a symbol: binary, octal, decimal, or hexadecimal. Each radix sign except decimal is prefixed to the resulting string. The default value is decimal.

11. If <sign> is a symbol that takes the form of 'sign, and <object> is a positive number without a positive sign, the positive sign is prefixed to the resulting string.

12. The <exactness> is a symbol: exact or inexact. Each returns a string of exact or inexact representation.

13. The resulting string is prefixed with <pre-string> and postfixed with <post-string>s.

Examples

(fox 129.995 -10 '(1))		-> "130.0     "
(fox 129.995 10 '(1))		-> "     130.0"
(fox 129.995 -10. #\* '(1))	-> "**130.0***"
(fox 129.995 10. #\* '(1))	-> "***130.0**"
(fox 129.995 10. #\* '(2))	-> "**130.00**"

(fox 4048 10 #\* '(hexadecimal))	-> "*****#xfd0"
(fox 4048 10 #\* '(hexadecimal sign))	-> "****#x+fd0"
(fox 4048 10 #\0 '(hexadecimal sign))	-> "#x+0000fd0"
(fox 4048.3125 15 #\* '(hexadecimal))		-> "****#i#xfd05/10"
(fox 4048.3125 15 #\* '(hexadecimal exact))	-> "******#xfd05/10"
(fox 4048 10 #\0 '(hexadecimal sign) `(,string-upcase . 0))	-> "#X+0000FD0"
(fox 4048 10 #\Z '(hexadecimal sign) `(,string-upcase . 0))	-> "ZZZZ#X+FD0"
(fox 4048 10 #\B '(hexadecimal sign) `(,string-upcase . 0))	-> "#X+BBBBFD0"

(fox 129.995 10 '(2 sign) '("$" . 0))		-> "  $+130.00"
(fox 129.995 10 '(2 sign) '("$" . -3))		-> "     $+130"

(fox 123000000 '(float))	    -> "1.23e+8"
(fox 123000000 '(5 float))	    -> "1.23000e+8"
(fox 1.23456789e+25 '(fixed))	    -> "12345678900000000000000000.0"

(fox 129.995 10. #\* '(0) '("|" . "|"))		->  "**|130.|**"
(fox 129.995 "|" 10. #\* '(0) "|")		-> "|***130.***|"

(fox 123456789.012 '(sign) '#(","))	-> "+123,456,789.012"
(fox 123456789 '(sign) '#("," 4))	-> "+1,2345,6789"
(fox "abcdefg" '(sign) '#(","))		-> "abcdefg"
(fox "abcdefg" '(sign) '#("::" 2))	-> "a::bc::de::fg"
(fox "abcdefg" '(sign) '#("::" -2))	-> "ab::cd::ef::g"

(fox '(#\a "str" s))   	       -> "(a str s)"
(fox '(#\a "str" s) write)     -> "(#\\a \"str\" s)"

(fox 'String "^" (current-output-port) 10 #\0 "$") -> ^0000String$
(fox 'String "^" #t 10 #\* "$")	       	      	   -> ^****String$

(define-record-type example
  (make-example num str)
  example?
  (num get-num set-num!)
  (str get-str set-str!))

(define (record-writer object string-port)
  (if (example? object)
      (begin (display (get-num object) string-port)
	     (display "-" string-port)
	     (display (get-str object) string-port))
      (display object string-port)))

(define (record-display object string-port)
  (display (get-num object) string-port)
  (display "-" string-port)
  (display (get-str object) string-port))

(let ((plus 12345678.901)
      (minus -123456.789)
      (ex (make-example 1234 "ex"))
      (file "today.txt"))
  (for-each (lambda (x y)
	      (fox x #t 10)
	      (fox y #t 15 '(2) (if (example? y) record-display display) '#(","))
	      (fox x #t 10)
	      (fox y #t 15 '(2) record-writer '#(","))
	      (newline))
	    (list "plus: " "minus: " "net: " "ex: " "file: ")
	    (list plus minus (+ plus minus) ex file)))
->
    plus:   12,345,678.90    plus:  12,345,678.901
   minus:     -123,456.79   minus:    -123,456.789
     net:   12,222,222.11     net:  12,222,222.112
      ex:         1234-ex      ex:         1234-ex
    file:       today.txt    file:       today.txt

References

[R5RS] Richard Kelsey, William Clinger, and Jonathan Rees: Revised(5) Report on the Algorithmic Language Scheme http://www.schemers.org/Documents/Standards/R5Rs/

[R6RS] Michael Sperber, R. Kent Dybvig, Matthew Flatt, and Anton von Straaten: Revised(6) Report on the Algorithmic Language Scheme http://www.r6rs.org

Copyright (c) 2012 Joo ChurlSoo.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ``Software''), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.