feedback soo (28 Mar 2004 11:58 UTC)
|
Re: feedback
Shiro Kawai
(28 Mar 2004 13:01 UTC)
|
Re: feedback
soo
(08 Apr 2004 16:11 UTC)
|
Re: feedback
Paul Schlie
(28 Mar 2004 18:04 UTC)
|
Re: feedback
soo
(30 Mar 2004 10:28 UTC)
|
Re: feedback
Paul Schlie
(30 Mar 2004 14:32 UTC)
|
Re: feedback
Paul Schlie
(30 Mar 2004 14:38 UTC)
|
Re: feedback
Paul Schlie
(30 Mar 2004 14:59 UTC)
|
Re: feedback
Paul Schlie
(30 Mar 2004 15:24 UTC)
|
Re: feedback
Paul Schlie
(30 Mar 2004 19:16 UTC)
|
Re: feedback
soo
(31 Mar 2004 13:46 UTC)
|
Re: feedback
Paul Schlie
(31 Mar 2004 14:58 UTC)
|
Thank all for thoughtful comments and indicating my wrong view. Especially, I express my thanks to Alan Watson for his thoughtful consideration. * From: Shiro Kawai <xxxxxx@lava.net> * Date: Thu, 25 Mar 2004 03:08:20 -1000 (HST) * Subj: Overloading >> >> | Why not have two distinct >> >> | procedures? >> >> Why must have two procedure? Inspite of the same processing course and return >> type(string). | I can think of one reason for not overloading the function. | Suppose I like to write a procedure that takes a list of objects, | and print out each element per line, left-padded to 20 columns, | using 'write' representation. | (defun (foo list-of-objects) (for-each (cut fmt <> 20 write "\n") list-of-objects)) | Oops, this fails if list-of-objects contains numeric values, right? | I think I suppose to write something like this: | (defun (foo list-of-objects) (for-each (lambda (elt) (if (number? elt) (fmt elt 20 "\n") (fmt elt 20 write "\n"))) list-of-objects)) | However, I think this is awkward. The trouble is, only the | programmer knows how she wants to treat a given object as | a numeric value or as just "one of Scheme values"---the program | can't deduct the programmer's intention purely from the type | of the object. | Having two distinct procedures at least help a programmer | to express the intention. At present, I partially agree with you. How about adding <show> parameter to number type? Then you can write it like this: (define (foo list-of-objects) (for-each (lambda (elt) (display (fmt elt 20 write "\n"))) list-of-objects)) (foo '(12 abc "string" #\a '(1 de "str" #\e))) 12 abc "string" #\a '(1 de "str" #\e) * From: Shiro Kawai <xxxxxx@lava.net> * Date: Thu, 25 Mar 2004 03:16:17 -1000 (HST) * Subj: <show> parameter >> * From: David Van Horn <xxxxxx@cs.uvm.edu> >> >> |And further, why are you allowed to pass in only display or write? >> >> FMT needs only display and write. | I might want to pass write-with-shared-structure (srfi-38), | in case if object has circular reference. Or to pass | my own version of write, which uses special formatting for | certain objects, suitable for my application. | I don't see what fmt gains by limiting <show> parameter to | display and write. | --shiro I used simply the <show> argument with intent to embody ~s and ~a directives of FORMAT. Now I agree with you, and I'll change the code of FMT from (list display write) to (cons display procedure?). Additional Changes: 1. The + of <plus> parameter is not a procedure but a symbol. 2. The number type also has the <show> option. * From: Alex Shinn <xxxxxx@synthcode.com> * Date: Fri, 26 Mar 2004 15:36:50 +0900 * Subj: Re: a preface | ... | So a title like "SRFI-54: Converting Objects to Strings" | would seem more appropriate. If possible, I'll change it to such a form. | I definitely agree that there should be a separate procedure for | numbers. Still, I can't agree. I am thinking over it. | If you choose radix as the first optional argument it can in | fact be an extended version of NUMBER->STRING. Actually, FMT is its extended version. | I think Paul Schlie gave | the most comprehensive list of number aspects here: http://srfi.schemers.org/srfi-48/mail-archive/msg00031.html | of which you're currently missing sign (which should allow for the | parentheses form used in finance) and commas. Thanks, I'll read it. | The other procedure could be OBJECT->STRING, ->STRING, or just STR (same | length!) if you want something short. | I also agree <show> should be allowed to be any procedure of two | arguments (object and port). If not, it should be omitted and just use | DISPLAY - users can write objects to string ports before passing them to OBJECT-> STRING if they need to override this. Now, I also agree. But how about a procedure of single argument (the first argument of FMT)? * From: "Bradd W. Szonye" <xxxxxx@szonye.com> * Date: Thu, 25 Mar 2004 10:59:58 -0800 * Subj: Re: Comments and some bugs | Jens Axel Søgaard wrote: > soo wrote: >> I would mark "-1." as an error, if a student wrote it. I don't think >> "-1." is correct mathematical syntax. | It's correct; it matches the syntax rule <decimal 10> --> <digit 10>+ . <digit 10>* #* <suffix> >> Besides the -1 given to FMT is an exact number. | But you're right about the problem here. I cannot agree. I think 0 is different from null. If there is <depth> parameter, I think the resulting string must have a decimal point. example: (fmt 123 10) " 123" (fmt 123 10 0) " #e123." (fmt 123 10 1) " #e123.0" (fmt 123.45 10) " 123.45" (fmt 123.45 10 0) " 123." (fmt 123.45 10 1) " 123.5" * From: bear <xxxxxx@sonic.net> * Date: Thu, 25 Mar 2004 10:05:20 -0800 (PST) * Subj: Re: Comments and some bugs | On Thu, 25 Mar 2004, soo wrote: >> R5RS says: If the written representation of a number has no exactness prefix, >> the constant may be either inexact or exact. It is inexact if it contains a >> decimal point, an exponent, or a "#" character in the place of a digit, >> otherwise it is exact. | This is true, but a number such as #e1.234 is still an exact number. | It could also have been written 1234/10000. | In general, if you rely on implementations to do the "Right thing" with | exact vs. inexact numbers, you will be disappointed or wind up with | a nonportable library. Some of them throw syntax errors on exactness | prefixes, some ignore exactness prefixes, some disallow decimal points | in exact numbers, some silently coerce to inexact even after reading an | exactness prefix if they encounter a decimal, etc. The behavior described | in R5RS is fully implemented, alas, only by a very few. >> > (fmt 1/2 5 0) >> | " 1." ; Huh? >> >> > (fmt -1 10 0) >> | " -1." ; Is this on purpose? >> >> Yes, it expresses that -1. is inexact number. | The problem here is that in both cases you should have an exact number. | You were given exact parameters, you had no need for inexact computations. | Why aren't the results exact? What display ought to give you here would | be simply "1" and "-1". >> (fmt 1/2 5 2 #\space (fmt 10)) " 0.5010" >> (fmt 1/2 5 2) " 0.50" >> The default value of padding character is #\space. | In these cases people have given you exact numbers and asked for | decimal format. The correct responses would be exact prefixes | followed by a decimal fractions, but I don't think the write procedure | of any known scheme will produce them. I'd need to pass my own write | procedure into FMT in order to get them, and FMT as specified doesn't | allow it. In fact, I don't know well where the <show> procedure is inserted and how many optional arguments is needed, and I think there is no reason for shame in learning. So tell me the way, please. Anyway, I've corrected FMT procedure as pointed out above. I've attached it in the end of this reply, and the followings are examples. (A) implementation (B) implementation (fmt 12.45 10 1) " 12.5" " 12.5" (fmt 12.45 10 1 'e) " #e12.5" " #e12.5" (fmt 12.45 10 1 'e '+) " #e+12.5" " #e+12.5" (fmt 12.45 10 1 'e '+ #\0) "#e+00012.5" "#e+00012.5" (fmt 12 10) " 12" " 12" (fmt 12 10 1) " #e12.0" " #e12.0" 3/2 3/2 1.5 (fmt 3/2 10) " 3/2" " 1.5" (fmt 3/2 10 2) " #e1.50" " 1.50" (fmt 3/2 10 2 'e) " #e1.50" " #e1.50" (inexact->exact 2.5) 5/2 3 (fmt 2.5 10 'e) " 5/2" " 3" (fmt 2.5 10 'e 3) " #e2.500" " #e2.500" (fmt 2.e-6) "2.e-06" "2.0e-6" (fmt 2.e-6 'e) "472236.../23611832..." "0" * From: Jens Axel Søgaard <xxxxxx@soegaard.net> * Date: Thu, 25 Mar 2004 19:07:38 +0100 * Subj: Re: Comments and some bugs | soo wrote: >> * From: Jens Axel Søgaard <xxxxxx@soegaard.net> >> > (fmt -5.0 0 #\space 10 + 'e) >> | . fmt: exact number cannot have a decimal point >> | 10 depth (and depth (eq? exactness (quote e))) ; Why not? >> > (fmt -5 0 #\space 10 + 'e) >> | . fmt: exact number cannot have a decimal point 10 depth (and depth (eq? exactness (quote e))) >> R5RS says: If the written representation of a number has no exactness prefix, >> the constant may be either inexact or exact. It is inexact if it contains a >> decimal point, an exponent, or a "#" character in the place of a digit, >> otherwise it is exact. | Yes? | What the above says is that if the reader sees a number *without exactness prefix* | such as "-5.0" then it by default shall read it as inexact if there is decimal dot. | If there is an exactness prefix the above rule doesn't apply since, it is obvious | whether the number read is exact or inexact. | Example: > (exact? #e-5.0) #t > (exact? -5.0) #f I've corrected it. And I've extended the spec of <depth> for (B) Implementation. <depth> is now exact integer. If <depth> is non-negative integer, then the exact sign (#e) can be prefixed. If <depth> is negative integer, then the exact sign is not used. Example: (fmt 123 10 1) " #e123.0" (fmt 123 10 -1) " 123.0" (fmt 123.45 10 1) " 123.5" (fmt 123.45 10 -1) " 123.5" (fmt 12.45 10 1 'e '+ #\0) "#e+00012.5" (fmt 12.45 10 -1 'e '+ #\0) Error: fmt: you didn't choose exact sign -1 depth (and depth (eq? exactness 'e) (< depth 0)) Thanks all. (define (fmt expr . rest) (if (number? expr) (receive (width depth char show radix plus exactness space . str-list) (opt-values rest (cons #f (lambda (x) (and (integer? x) (exact? x)))) (cons #f (lambda (x) (and (integer? x) (exact? x)))) (cons #f char?) (cons #f procedure?) (list 'd 'b 'o 'x) (cons #f (lambda (x) (eq? x '+))) (cons #f (lambda (x) (memq x '(e i)))) (cons #f (lambda (x) (and (list? x) (<= 1 (length x) 2) (every (lambda (x) (and (integer? x) (exact? x) (<= 0 x))) x))))) (arg-ors ("fmt: bad argument" str-list (not (every string? str-list))) ("fmt: non-decimal cannot be inexact" radix (and (memq radix '(b o x)) (or depth (and (inexact? expr) (not (eq? exactness 'e))) (eq? exactness 'i)))) ("fmt: you didn't choose exact sign" depth (and depth (eq? exactness 'e) (< depth 0))) ("fmt: unnecessary padding character" char (and char (not width)))) (let* ((width (or width 0)) (char (or char #\space)) (sign (if (< width 0) '- '+)) (exact-sign (and (and depth (<= 0 depth) (or (eq? exactness 'e) (and (exact? expr) (not (eq? exactness 'i))))) "#e")) (str (number->string (if (or (not depth) (<= 0 depth)) (if exact-sign (if (exact? expr) (exact->inexact expr) expr) (if exactness (if (eq? exactness 'e) (if (inexact? expr) (inexact->exact expr) expr) (if (exact? expr) (exact->inexact expr) expr)) expr)) (if exactness (if (eq? exactness 'e) (if (inexact? expr) (inexact->exact expr) expr) (if (exact? expr) (exact->inexact expr) expr)) (if (and depth (exact? expr)) (exact->inexact expr) expr))) (cdr (assq radix '((b . 2) (d . 10) (o . 8) (x . 16)))))) (str (if depth (let ((depth (abs depth)) (e-index (or (string-index str #\e) (string-index str #\E))) (+-index (string-index str #\+ 1)) (--index (string-index str #\- 1))) (define (mold str dep) (let ((len (string-length str)) (index (string-index str #\.))) (if index (let ((d-len (- len (+ index 1)))) (if (<= d-len dep) (string-append str (make-string (- dep d-len) #\0)) (mold (number->string (let ((num (string->number (substring str 0 (+ (if (= dep 0) 0 1) index dep))))) ((if (< num 0) - +) num (if (< 4 (string->number (string (string-ref str (+ 1 index dep))))) (expt 0.1 dep) 0)))) dep))) (string-append str "." (make-string dep #\0))))) (cond (e-index (string-append (mold (substring str 0 e-index) depth) (substring str e-index (string-length str)))) (+-index (string-append (mold (substring str 0 +-index) depth) "+" (mold (substring str (+ 1 +-index) (- (string-length str) 1)) depth) (string (string-ref str (- (string-length str) 1))))) (--index (string-append (mold (substring str 0 --index) depth) "-" (mold (substring str (+ 1 --index) (- (string-length str) 1)) depth) (string (string-ref str (- (string-length str) 1))))) (else (mold str depth)))) str)) (str (if (and (< 0 (real-part expr)) (not (eqv? #\+ (string-ref str 0))) plus) (string-append "+" str) str)) (len (string-length str)) (lt (if space (car space) 0)) (rt (if (and space (not (null? (cdr space)))) (cadr space) 0)) (pad (- (abs width) (+ len lt rt (if exact-sign 2 0))))) (apply string-append (make-string lt #\space) (cond ((<= pad 0) (string-append (or exact-sign "") str)) ((eq? sign '+) (if (and (eqv? char #\0) (or (eqv? #\+ (string-ref str 0)) (eqv? #\- (string-ref str 0)))) (string-append (or exact-sign "") (string (string-ref str 0)) (make-string pad char) (substring str 1 len)) (string-append (make-string pad char) (or exact-sign "") str))) (else (string-append (or exact-sign "") str (make-string pad char)))) (make-string rt #\space) str-list))) (receive (width count char show case space . str-list) (opt-values rest (cons #f (lambda (x) (and (integer? x) (exact? x)))) (cons #f (lambda (x) (and (integer? x) (exact? x)))) (cons #f char?) (cons display procedure?) (cons #f (lambda (x) (memq x '(d u t)))) (cons #f (lambda (x) (and (list? x) (<= 1 (length x) 2) (every (lambda (x) (and (integer? x) (exact? x) (<= 0 x))) x))))) (arg-ors ("fmt: bad argument" str-list (not (every string? str-list))) ("fmt: unnecessary padding character" char (and char (not width)))) (let* ((width (or width 0)) (char (or char #\space)) (sign (if (< width 0) '- '+)) (str (if (or (eq? show display) (eq? show write)) (get-output-string (let ((str-port (open-output-string))) (show expr str-port) str-port)) (show expr))) (str (if (and count (< (abs count) (string-length str))) (if (< count 0) (string-take-right str (abs count)) (string-take str count)) str)) (str (if case ((cdr (assq case `((d . ,string-downcase) (u . ,string-upcase) (t . ,string-titlecase)))) str) str)) (lt (if space (car space) 0)) (rt (if (and space (not (null? (cdr space)))) (cadr space) 0)) (pad (- (abs width) (+ (string-length str) lt rt)))) (apply string-append (make-string lt #\space) (cond ((<= pad 0) str) ((eq? sign '+) (string-append (make-string pad char) str)) (else (string-append str (make-string pad char)))) (make-string rt #\space) str-list))))) -- INITERM