[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: feedback



Hi Soo,

If you have the chance, it may be helpful to read through ALL of the
discussions related to the earlier SRFI-48 "Re: Format strings are wrong"
postings, as they may be helpful. (as previously noted, it may still be a
good idea to first define your broader objectives more formally to help
delineate your goals and philosophy in order to help focus the discussions
productively; please do not interpret these comments as being antagonistic,
as I honestly believe we'd like both like to see the same/similar thing
enabled).

Few observations:

- personally, believe that some lowest (simplest) level of object->string
formatting should be defined to enable the basic strings to be composed from
lists of arbitrary scheme objects, which default to utilizing their most
likely string equivalent representations, likely those expected by (read).

- as observed in the earlier srfi-48 discussions, it may even be better
(both more general, and efficient) to define that resulting format functions
yield string-ports, rather than strings; which could then even be made more
general if formatting functions themselves were able to accept string-ports,
such that more complex hierarchically defined formats may be defined as
desired.

- lastly, although personally I too would like format specifications to be
as succinct as possible, I suspect that all format specifications containing
more than a single specifier should be tagged with at least a single letter
semi-descriptive symbol to both give a hint as to what the specified
controls, and to enable them to be only defined as required in arbitrary
ordered lists as convenient to the author, and/or to enable their more
flexible construction.

With a little luck, the above is hopefully also be consistent with your
goals for this srfi as well?

-paul-

> From: soo <tilde@xxxxxxxxxxx>
> Date: 28 Mar 2004 20:58:51 +0900
> To: srfi-54@xxxxxxxxxxxxxxxxx
> Subject: feedback
> Resent-From: srfi-54@xxxxxxxxxxxxxxxxx
> Resent-Date: Sun, 28 Mar 2004 13:58:22 +0200 (DFT)
> 
> 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 <shiro@xxxxxxxx>
> * 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 <shiro@xxxxxxxx>
> * Date: Thu, 25 Mar 2004 03:16:17 -1000 (HST)
> * Subj: <show> parameter
> 
>>> * From: David Van Horn <dvanhorn@xxxxxxxxxx>
>>>>> |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 <foof@xxxxxxxxxxxxx>
> * 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" <bradd+srfi@xxxxxxxxxx>
> * 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 <bear@xxxxxxxxx>
> * 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 <jensaxel@xxxxxxxxxxxx>
> * Date: Thu, 25 Mar 2004 19:07:38 +0100
> * Subj: Re: Comments and some bugs
> 
> | soo wrote:
>>> * From: Jens Axel Søgaard <jensaxel@xxxxxxxxxxxx>
> 
>>>> (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
>