Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Simple Function Question

36 views
Skip to first unread message

Jared Brogni

unread,
May 17, 1999, 3:00:00 AM5/17/99
to
I'm looking to take a number string (i.e. "12") and turn it into the
actual integer value (12). I've only got a single lisp book and it
doesn't talk about that. Can anyone help me out and tell me how I can
get the interger value of a string of numbers?

Thank you,
Jared Brogni


Christopher R. Barry

unread,
May 17, 1999, 3:00:00 AM5/17/99
to
Jared Brogni <jbr...@sgi.com> writes:

> Can anyone help me out and tell me how I can get the interger value
> of a string of numbers?

READ-FROM-STRING

Christopher

Barry Margolin

unread,
May 17, 1999, 3:00:00 AM5/17/99
to
In article <874slbz...@2xtreme.net>,

That's overkill. See my response for a more appropriate function.

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.

Barry Margolin

unread,
May 17, 1999, 3:00:00 AM5/17/99
to
In article <37406B26...@sgi.com>, Jared Brogni <jbr...@sgi.com> wrote:
>I'm looking to take a number string (i.e. "12") and turn it into the
>actual integer value (12). I've only got a single lisp book and it
>doesn't talk about that. Can anyone help me out and tell me how I can

>get the interger value of a string of numbers?

Look up the function PARSE-INTEGER in CLTL or the CLHS.

Tim Bradshaw

unread,
May 17, 1999, 3:00:00 AM5/17/99
to
* Christopher R Barry wrote:
> Jared Brogni <jbr...@sgi.com> writes:
>> Can anyone help me out and tell me how I can get the interger value
>> of a string of numbers?

> READ-FROM-STRING

Bad answer. Unless you know already what is in the string (so you've
already parsed it pretty much) or you're willing to handle arbitrary
reader errors and deal with completely undetermined return types, and
you're being sufficiently careful with the current readtable, reader
control variables, this is grotesquely unsafe code. If you control
all these things it's merely grotesquely bad code.

Try PARSE-INTEGER instead, or write your own integer parser (it's not
hard). Both solutions are better than READ-FROM-STRING.

--tim

Penny Century

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
In article <ey3n1z3...@lostwithiel.tfeb.org>, Tim Bradshaw wrote:
>* Christopher R Barry wrote:
>> Jared Brogni <jbr...@sgi.com> writes:
>>> Can anyone help me out and tell me how I can get the interger value
>>> of a string of numbers?
>
>> READ-FROM-STRING
>
>Bad answer.

<Snip good reasons why>

>Try PARSE-INTEGER instead, or write your own integer parser (it's not
>hard). Both solutions are better than READ-FROM-STRING.

I've just used read string to do a similar thing with floats. Seeing as it's
disposable code to be used once by me, I'll forgive myself, but looking at
"ANSI Common Lisp" I don't see a parse-float. Should I really have written a
float parser?

Penny,
prolly hasn't R'ed enuff FMs
--
`I know it's out of fashion and a trifle uncool,
But I can't help it, I'm a romantic fool.'
Martha & the Muffins - Echo Beach.

Russell Senior

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
>>>>> "Kent" == Kent M Pitman <pit...@world.std.com> writes:

Kent> See WITH-STANDARD-IO-SYNTAX for packaged control of a great
Kent> many. But you should make sure to consider setting *READ-EVAL*
Kent> to NIL if the application is "exposed" in any way. [...]

The following is a function I have been using recently to `numerate' a
list of strings that were obtained elsewhere (remember the
`split-sequence' thread?). I have been adding condition handling to
it as I have encountered problems, and I just added the *read-eval*
protection as a result of this thread. I would be glad to hear any
criticisms of it:

(defun numerate-list-of-strings (list-of-strings)
"This function tries to convert strings to numbers, for each member
of the list LIST-OF-STRINGS, returning a new list. If the string
is not a number, than the original string is retained."
(with-standard-io-syntax
(let ((*read-eval* nil))
(map 'list
#'(lambda (str)
(cond ((null str) nil)
((string= str "") nil)
(t (multiple-value-bind (val pos)
(handler-case
(read-from-string str)
(system::simple-stream-error
(condition)
(values nil 0 condition))
(system::simple-end-of-file ; catch embedded #\#
(condition)
(values nil 0 condition))
(system::simple-package-error ; catch embedded #\:
(condition)
(values nil 0 condition)))
(if (and (numberp val)
(handler-case
(read-from-string str t nil :start pos)
(system::simple-end-of-file
(condition)
(values t condition))
(:no-error
(val pos)
(declare (ignore val pos))
nil)))
val
str)))))
list-of-strings))))

(numerate-list-of-strings '("50" "#.(* 5 10)" "27e7"))
=> (50 "#.(* 5 10)" 2.7E8)


--
Russell Senior
sen...@teleport.com

Barry Margolin

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
In article <sfwzp32...@world.std.com>,
Kent M Pitman <pit...@world.std.com> wrote:

>Hrvoje Niksic <hni...@srce.hr> writes:
>
>> Kent M Pitman <pit...@world.std.com> writes:
>>
>> > It's a sad thing there's no PARSE-FLOAT, since that's a lot harder
>> > to write than PARSE-INTEGER. I think we should add one.
>>
>> Maybe a general PARSE-NUMBER with provisions to allow integers,
>> floats, or even complex numbers would be more appropriate.
>
>Supposing you were designing this. What would you do about complexes?
>Remember that the problem is that often these are being used for non-lisp
>data.

Probably the right solution to this would be something more like C's
scanf(). For those of you unfamiliar with C, it's sort of the opposite of
printf(), which is analogous to Common Lisp's FORMAT. You provide a data
template that specifies the type of data to be found at various places in
the input, and it uses the appropriate parser.

Wade Humeniuk

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
> Since you're in control of your own readtable, if you know you have
> not exposed it to #. for any other reason that might have changed the
> readtable, just peeking at the first character and seeing that it is a
> digit or a "+" or a "-" or a "." might be sufficient to assure it's
> not something bad to read and still allow you to read various kinds of
> numbers. It's a sad thing there's no PARSE-FLOAT, since that's a lot

> harder to write than PARSE-INTEGER. I think we should add one.
>
>

Along the same line I have been coding parsing routines for time and
distance that accept strings like:

"1:36:12.2", "2hr36s", "10000m" "10.2mi", .....

These strings were being entered by users and must withstand
mistakes.

I have found the built in support in CL lacking. I ended up coding up my
own parsing routines utilizing read-char. I tried the same approach
with macro characters but I found it was just as complex. It would be
nice if CL had some better built-in parsing routines. It took a
relatively long time to code this portion of my application mostly
because of my indecision of how to do it. I have included the code
to parse time below. If anyone has some better suggestion I am
all ears.

The main entry point is read-time-from-string which takes strings
like:
"32.2222s"
"1:10"
"21"
"10hr90m"

and return the time in hundreths of seconds.

Wade Humeniuk


;; Time routines. You will have to create your own condition
;; invalid-time-format

(defun signal-time-reader-error ()
(declare (special *time-string*))
(error (make-condition 'invalid-time-format :invalid-format
*time-string*))
nil)

(defun time-list-to-hundreths (time-list)
(let ((seconds (first time-list))
(minutes (second time-list))
(hours (third time-list)))
(if (and time-list
(< (length time-list) 4)
(realp seconds)
(or (null minutes) (integerp minutes))
(or (null hours) (integerp hours)))
(+ (round (* seconds 100))
(* (if minutes minutes 0) 6000)
(* (if hours hours 0) 360000))
(signal-time-reader-error))))

(defun read-hms-time-from-string (*time-string*)
(declare (special *time-string*))
(with-input-from-string (stream *time-string*)
(read-hms-time stream)))

(defun read-time-number (stream)
(flet ((char-to-integer (c) (position c "0123456789")))
(let ((temp)
(in-decimal)
(decimal-depth 0)
(c))
(loop
(setf c (read-char stream nil nil))
(cond
((not c) (if temp (return temp) (signal-time-reader-error)))
((digit-char-p c)
(unless temp (setf temp 0))
(cond
(in-decimal
(incf decimal-depth 1)
(incf temp (/ (char-to-integer c) (expt 10 decimal-depth))))
(t (setf temp (+ (* temp 10) (char-to-integer c))))))
((char= #\. c)
(cond
((not in-decimal) (setf in-decimal t decimal-depth 0))
(in-decimal (signal-time-reader-error))))
(t
(unread-char c stream)
(if temp (return temp) (signal-time-reader-error))))))))

(defun read-hms-time (stream)
(let ((hours)(minutes)(seconds)(temp)(c))
(flet ((reset () (setf temp nil)))
(loop
(setf c (read-char stream nil nil))
(cond
((not c)
(if temp
(signal-time-reader-error)
(return (time-list-to-hundreths (list (or seconds 0) (or minutes
0) (or hours 0))))))
((or (digit-char-p c) (char= c #\.))
(when temp (signal-time-reader-error))
(unread-char c stream)
(setf temp (read-time-number stream))
(if (null temp) (signal-time-reader-error)))
((char-equal #\h c)
(cond
((or (not temp) hours) (signal-time-reader-error))
(t
(setf hours temp)
(reset))))
((char-equal #\m c)
(cond
((or (not temp) minutes) (signal-time-reader-error))
(t
(setf minutes temp)
(reset))))
((char-equal #\s c)
(cond
((or (not temp) seconds) (signal-time-reader-error))
(t
(setf seconds temp)
(reset))))
((char= #\Space c) nil)
(t
(signal-time-reader-error)))))))

(defun read-colon-time-from-string (*time-string*)
(declare (special *time-string*))
(with-input-from-string (stream *time-string*)
(read-colon-time stream)))

(defun read-colon-time (stream)
(let ((time-list)(temp)(c))
(flet ((reset () (setf temp nil)))
(loop
(setf c (read-char stream nil))
(cond
((not c)
(when temp (push temp time-list))
(return (time-list-to-hundreths time-list)))
((or (digit-char-p c) (char= #\. c))
(if temp (signal-time-reader-error) (setf temp 0))
(unread-char c stream)
(setf temp (read-time-number stream))
(unless temp (signal-time-reader-error)))
((char-equal #\: c)
(cond
((not temp) (signal-time-reader-error))
(t (push temp time-list) (reset))))
((char= #\Space c) t)
(t
(signal-time-reader-error)))))))

(defun read-time-from-string (time-string)
(if (and time-string (> (length time-string) 0))
(restart-case
(handler-bind ((invalid-time-format
(lambda (condition)
(declare (ignore condition))
(invoke-restart 'restart-hms-time))))
(read-colon-time-from-string time-string))
(restart-hms-time () (read-hms-time-from-string time-string)))
nil))


(defun time-string (time)
(if (and time (not (zerop time)))
(let* ((hours (floor (/ time 360000)))
(minutes (floor (/ (- time (* hours 360000)) 6000)))
(hundreths-seconds (- time (* hours 360000) (* minutes 6000)))
(seconds (floor (/ hundreths-seconds 100)))
(hundreths (mod hundreths-seconds 100)))
(with-output-to-string (stream)
(cond
((and (zerop hours)
(zerop minutes))
(format stream "~2,'0D" seconds))
((zerop hours)
(format stream "~D:~2,'0D" minutes seconds))
(t
(format stream "~D:~2,'0D:~2,'0D"
hours minutes seconds)))
(if (not (zerop hundreths))
(format stream ".~2,'0D" hundreths))))
nil))

Kent M Pitman

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Barry Margolin <bar...@bbnplanet.com> writes:

> In article <sfwzp32...@world.std.com>,
> Kent M Pitman <pit...@world.std.com> wrote:
> >Hrvoje Niksic <hni...@srce.hr> writes:
> >
> >> Kent M Pitman <pit...@world.std.com> writes:
> >>

> >> > It's a sad thing there's no PARSE-FLOAT, since that's a lot harder
> >> > to write than PARSE-INTEGER. I think we should add one.
> >>

> >> Maybe a general PARSE-NUMBER with provisions to allow integers,
> >> floats, or even complex numbers would be more appropriate.
> >
> >Supposing you were designing this. What would you do about complexes?
> >Remember that the problem is that often these are being used for non-lisp
> >data.
>
> Probably the right solution to this would be something more like C's
> scanf(). For those of you unfamiliar with C, it's sort of the opposite of
> printf(), which is analogous to Common Lisp's FORMAT. You provide a data
> template that specifies the type of data to be found at various places in
> the input, and it uses the appropriate parser.

You miss my point. I was asking about the fact that the Lisp printed
representation a la #C(...) would differ from the notation other programs
would probably want to use. I was asking whether a PARSE-NUMBER's
"%c" or "~c" for reading would correspond to Lispy syntax, C syntax,
or something else. Or whether you'd do "#C(%i %i)". Or whether
you'd simulate #C without actually calling the # readmacro to avoid
security leaks. Or whether you'd use 3+5i as in the Lisp potential
number thing. Part of the issue is that while C has scanf be the
opposite of printf, Lisp would only have an opposite if in fact
you used the #C(...) notation, which I suspect would annoy some people
in interchange with other languages. You could make a variant of WRITE
which printed everything as it does now except complexes, but that would
have its own problem. You could have a reader variable saying
*PRINT-SCANFLY*
(make sure you break the syllables between the "F" and the "L" to see
what word I got that from) that only complexes looked at and that no
other printers looked at. My point wasn't that it wasn't doable.
I was soliciting advice about what design criterion to use to pick
among the rich set of options for including into the template's set
of standard parse-tools.


Kent M Pitman

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
"Wade Humeniuk" <hume...@cadvision.com> writes:

> Along the same line I have been coding parsing routines for time and
> distance that accept strings like:
>
> "1:36:12.2", "2hr36s", "10000m" "10.2mi", .....

I recall a proposal a long time ago to make

(setf (format nil "~D:~D:~D" x y z) "1:36:12.2")

work. [Don't think too hard about it. It has a lot of problems.
But it *was* cute. A more practical solution we *should* consider
would be regular expression processing.]

Kent M Pitman

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Tim Bradshaw <t...@tfeb.org> writes:

>
> * Christopher R Barry wrote:
> > Jared Brogni <jbr...@sgi.com> writes:
> >> Can anyone help me out and tell me how I can get the interger value
> >> of a string of numbers?
>
> > READ-FROM-STRING
>

> Bad answer. Unless you know already what is in the string (so you've
> already parsed it pretty much) or you're willing to handle arbitrary
> reader errors and deal with completely undetermined return types, and
> you're being sufficiently careful with the current readtable, reader
> control variables, this is grotesquely unsafe code. If you control
> all these things it's merely grotesquely bad code.

READ-FROM-STRING also permits #. which means you can run arbitrary
code, so is subject to trojan horses as well.


Christopher R. Barry

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Barry Margolin <bar...@bbnplanet.com> writes:

[...]
> >READ-FROM-STRING
>
> That's overkill.

Tim Bradshaw <t...@tfeb.org> writes:

[...]
> > READ-FROM-STRING
>
> Bad answer.

I guess for this guy's purpose it is, but what if he decides he wants
to read floats or rationals or even complex-nums from a string? Would
you advise him to write a separate parser for every different type
since CL only provides an integer parser?

> Unless you know already what is in the string (so you've already
> parsed it pretty much)

It was already known what kind of data would be in the string in this
case, which does mean that PARSE-INTEGER was more appropriate, but I
still don't see READ-FROM-STRING being too sinful (yet).

> or you're willing to handle arbitrary reader errors and deal with
> completely undetermined return types, and you're being sufficiently
> careful with the current readtable, reader control variables, this
> is grotesquely unsafe code. If you control all these things it's
> merely grotesquely bad code.

Under what circumstances do you feel READ-FROM-STRING is appropriate
instead of spending your time to construct a custom string parser for
every single different data type you plan to read? If you want to
avoid errors, why not just wrap everything in an UNWIND-PROTECT or
IGNORE-ERRORS form?

Christopher

Tim Bradshaw

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
* Christopher R Barry wrote:

> Under what circumstances do you feel READ-FROM-STRING is appropriate
> instead of spending your time to construct a custom string parser for
> every single different data type you plan to read? If you want to
> avoid errors, why not just wrap everything in an UNWIND-PROTECT or
> IGNORE-ERRORS form?

I think it's a furry boundary. But I hope you realise that it's *not*
just a case of UNWIND-PROTECT? You need to do a lot more than that to
be safe, like control all the reader variables.

--tim

Kent M Pitman

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Tim Bradshaw <t...@tfeb.org> writes:

See WITH-STANDARD-IO-SYNTAX for packaged control of a great many.
But you should make sure to consider setting *READ-EVAL* to NIL if

the application is "exposed" in any way.

Since you're in control of your own readtable, if you know you have


not exposed it to #. for any other reason that might have changed the
readtable, just peeking at the first character and seeing that it is a
digit or a "+" or a "-" or a "." might be sufficient to assure it's
not something bad to read and still allow you to read various kinds of

numbers. It's a sad thing there's no PARSE-FLOAT, since that's a lot

Hrvoje Niksic

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Kent M Pitman <pit...@world.std.com> writes:

> It's a sad thing there's no PARSE-FLOAT, since that's a lot harder
> to write than PARSE-INTEGER. I think we should add one.

Maybe a general PARSE-NUMBER with provisions to allow integers,

Kent M Pitman

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Hrvoje Niksic <hni...@srce.hr> writes:

Supposing you were designing this. What would you do about complexes?

Hrvoje Niksic

unread,
May 18, 1999, 3:00:00 AM5/18/99
to
Kent M Pitman <pit...@world.std.com> writes:

> Hrvoje Niksic <hni...@srce.hr> writes:
>
> > Kent M Pitman <pit...@world.std.com> writes:
> >
> > > It's a sad thing there's no PARSE-FLOAT, since that's a lot harder
> > > to write than PARSE-INTEGER. I think we should add one.
> >
> > Maybe a general PARSE-NUMBER with provisions to allow integers,
> > floats, or even complex numbers would be more appropriate.
>
> Supposing you were designing this. What would you do about
> complexes?

I'm probably the wrong person to ask about designing this, since I'm
only a beginner at Common Lisp (I've played with Emacs Lisp a lot.)
People more knowledgable about symbolic representation of numbers
might be better suited to answer this question.

Having said that, I suppose you could allow PARSE-NUMBER to grok
strings such as "2+3i", or "#C(1 2)", or "2 + 3i" as complex numbers.
The only problem (I see) with this is that some of these cases are not
readable by the regular reader. It might be OK for PARSE-NUMBER to
accept what the reader doesn't, or it might not. I don't know.

The reason I proposed this is that it seems like a bad idea to
specialize one function for parsing one numeric type. If we introduce
the sorely-needed PARSE-FLOAT, then we could also have PARSE-COMPLEX,
PARSE-RATIONAL, and whatnot. It makes more sense to just allow more
keywords in PARSE-NUMBER, like :allow-rational or :allow-complex.

Christopher R. Barry

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
Kent M Pitman <pit...@world.std.com> writes:

> I recall a proposal a long time ago to make
>
> (setf (format nil "~D:~D:~D" x y z) "1:36:12.2")
>
> work. [Don't think too hard about it. It has a lot of problems.

Couldn't stop myself. Were these problems along the lines of
constraining and defining the details of how exactly this would work
or otherwise?

> But it *was* cute. A more practical solution we *should* consider
> would be regular expression processing.

We need that to, but I'm a SETF fan and like the mind-set. Stuff like
this really makes you imagine the possibilities....

Christopher

Marco Antoniotti

unread,
May 19, 1999, 3:00:00 AM5/19/99
to

Hrvoje Niksic <hni...@srce.hr> writes:

> Kent M Pitman <pit...@world.std.com> writes:
>

> > Hrvoje Niksic <hni...@srce.hr> writes:
> >
> > > Kent M Pitman <pit...@world.std.com> writes:
> > >

There is a PARSE-FLOAT in the AI.Repository.

Cheers

--
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa

Kent M Pitman

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
cba...@2xtreme.net (Christopher R. Barry) writes:

> Kent M Pitman <pit...@world.std.com> writes:
>

> > I recall a proposal a long time ago to make
> >
> > (setf (format nil "~D:~D:~D" x y z) "1:36:12.2")
> >
> > work. [Don't think too hard about it. It has a lot of problems.
>
> Couldn't stop myself. Were these problems along the lines of
> constraining and defining the details of how exactly this would work
> or otherwise?

Thinks about (setf (format nil "~D~D" x y) "123")

> > But it *was* cute. A more practical solution we *should* consider
> > would be regular expression processing.
>
> We need that to, but I'm a SETF fan and like the mind-set. Stuff like
> this really makes you imagine the possibilities....

Yeah, just because you can't implement a proposal as spec'd is no reason
to stop thinking about it. Often such good ideas can be repaired if the
right person puts their mind to it. I know I throw a lot of cold water
on half-baked proposals people make here by telling you how badly those
things failed in the past, but mostly it's to avoid us taking exactly the
same path in the past without learning from it.

Lisp is full of stuff that can't always be done perfectly on the first
try but that we work as a community to refine through use. If you
don't dream and you just implement what's really obvious how to do on
the day you do the design, you get things like C++, which aggressively
refused to do anything where the number of instructions couldn't be bounded
in some way. That didn't change the set of problems people wanted to solve
with it--it only meant you had the same climb ahead with less of a leg up.


Sam Steingold

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
>>>> In message <87ogjii...@pc-hrvoje.srce.hr>
>>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
>>>> Sent on 18 May 1999 18:34:41 +0200

>>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
>>
>> strings such as "2+3i",

oh please! "2+3i" is a complex number while "2+3j" is a symbol.
who was the wise guy who inflicted this brain damage on Scheme?!

>> "#C(1 2)", or

only Lisp uses this format, and I thought we were talking (in part)
about communicating with other programs.

>> "2 + 3i" as complex numbers.

so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?

--
Sam Steingold (http://www.goems.com/~sds) running RedHat6.0 GNU/Linux
Micros**t is not the answer. Micros**t is a question, and the answer is Linux,
(http://www.linux.org) the choice of the GNU (http://www.gnu.org) generation.
In the race between idiot-proof software and idiots, the idiots are winning.

Wade Humeniuk

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
> Think about (setf (format nil "~D~D" x y) "123")

How about something like the following syntax?

(defun read-time-from-string (time-string)
(multipule-value-parse-string ((hours (integer 0 *))
(minutes (integer 0 *)
:maximum-field-length 2 :radix 10)
(seconds (decimal-real 0 *)))
time-string
(declare (parser allow-whitespace-between-elements))
(("~S" seconds)
("~S:~S" minutes seconds)
("~S:~S:~S" hours minutes seconds)
("~Ss" seconds)
("~Sm~Ss" minutes seconds)
("~Sh~Sm~Ss) hours minutes seconds)
(t (signal-time-read-error)))
(list hours minutes seconds)))

You can specify valid strings and things like field lengths to get around
abiguities lin expressions caused by

(setf (format nil "~D~D" x y) "123")

to do this you could

(multiple-value-parse-string ((x integer :maximum-field-length 2) (y
integer))
"123"
(("~S~S") x y)
(values x y))

would return x = 12 y = 3

Wade


Gareth McCaughan

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
Kent Pitman wrote:

> I recall a proposal a long time ago to make
>
> (setf (format nil "~D:~D:~D" x y z) "1:36:12.2")
>
> work. [Don't think too hard about it. It has a lot of problems.

> But it *was* cute. A more practical solution we *should* consider

> would be regular expression processing.]

Yow. How about extending it a little further?

(progn (setf (* x x) 4) x) ==> either 2 or -2

(progn (declare (type (integer 1 *) x y z)
(type (integer 3 *) n))
(setf (+ (expt x n) (expt y n) (- (expt z n))) 0)
(list x y z n)) ==> ERROR: That equation has no solutions.

:-)

--
Gareth McCaughan Dept. of Pure Mathematics & Mathematical Statistics,
gj...@dpmms.cam.ac.uk Cambridge University, England.

Hrvoje Niksic

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
Sam Steingold <s...@goems.com> writes:

> >>>> In message <87ogjii...@pc-hrvoje.srce.hr>
> >>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
> >>>> Sent on 18 May 1999 18:34:41 +0200
> >>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
> >>
> >> strings such as "2+3i",
>
> oh please! "2+3i" is a complex number while "2+3j" is a symbol.

"2+3j" is not a symbol here because we're talking about a hypothetical
PARSE-NUMBER, not about the Lisp reader. Anyway, you could also allow
"2+3j", for all I care. I don't like being dragged too far into this
discussion -- it's not like I have any idea why 2+3i would be any
worse than 2+3j.

> >> "#C(1 2)", or
>
> only Lisp uses this format, and I thought we were talking (in part)
> about communicating with other programs.

Again, I don't see harm in (parse-number "#C(1 2)") returning #C(1 2).

> >> "2 + 3i" as complex numbers.
>
> so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?

The latter.

Marco Antoniotti

unread,
May 19, 1999, 3:00:00 AM5/19/99
to

Gareth McCaughan <gj...@dpmms.cam.ac.uk> writes:

> Kent Pitman wrote:
>
> > I recall a proposal a long time ago to make
> >
> > (setf (format nil "~D:~D:~D" x y z) "1:36:12.2")
> >
> > work. [Don't think too hard about it. It has a lot of problems.
> > But it *was* cute. A more practical solution we *should* consider
> > would be regular expression processing.]
>
> Yow. How about extending it a little further?
>
> (progn (setf (* x x) 4) x) ==> either 2 or -2
>
> (progn (declare (type (integer 1 *) x y z)
> (type (integer 3 *) n))
> (setf (+ (expt x n) (expt y n) (- (expt z n))) 0)
> (list x y z n)) ==> ERROR: That equation has no solutions.
>

I have a better one.

(equalp P NP) => t nil

Cheers :)

Sam Steingold

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
>>>> In message <87zp31c...@pc-hrvoje.srce.hr>

>>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
>>>> Sent on 19 May 1999 17:05:18 +0200

>>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
>> Sam Steingold <s...@goems.com> writes:
>> > >>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
>> > >> strings such as "2+3i",
>> > oh please! "2+3i" is a complex number while "2+3j" is a symbol.
>>
>> "2+3j" is not a symbol here because we're talking about a
>> hypothetical PARSE-NUMBER, not about the Lisp reader. Anyway, you

all right, an error then.

>> could also allow "2+3j", for all I care. I don't like being dragged

what about "2i"? "2i+3"? "2i+4j"?

>> too far into this discussion -- it's not like I have any idea why
>> 2+3i would be any worse than 2+3j.

what about "2+3k"? how about "1+2i+3j+4k"?

>> > >> "2 + 3i" as complex numbers.
>> > so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?
>> The latter.

why? you mean `parse-number' will return something different from
`parse-integer'?

--
Sam Steingold (http://www.goems.com/~sds) running RedHat6.0 GNU/Linux
Micros**t is not the answer. Micros**t is a question, and the answer is Linux,
(http://www.linux.org) the choice of the GNU (http://www.gnu.org) generation.

A man paints with his brains and not with his hands.

Barry Margolin

unread,
May 19, 1999, 3:00:00 AM5/19/99
to
In article <sfwg14t...@world.std.com>,

Kent M Pitman <pit...@world.std.com> wrote:
>cba...@2xtreme.net (Christopher R. Barry) writes:
>
>> Kent M Pitman <pit...@world.std.com> writes:
>>
>> > I recall a proposal a long time ago to make
>> >
>> > (setf (format nil "~D:~D:~D" x y z) "1:36:12.2")
>> >
>> > work. [Don't think too hard about it. It has a lot of problems.
>>
>> Couldn't stop myself. Were these problems along the lines of
>> constraining and defining the details of how exactly this would work
>> or otherwise?
>
>Thinks about (setf (format nil "~D~D" x y) "123")

The problem is no different from something like C's sscanf("123", "%d%d",
&x, &y). Obviously an input parser won't be a complete inverse of an
output formatter. But this doesn't mean that the use of SETF of FORMAT as
the interface is flawed.

Christopher R. Barry

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Barry Margolin <bar...@bbnplanet.com> writes:

> >Thinks about (setf (format nil "~D~D" x y) "123")
>
> The problem is no different from something like C's sscanf("123", "%d%d",
> &x, &y). Obviously an input parser won't be a complete inverse of an
> output formatter. But this doesn't mean that the use of SETF of FORMAT as
> the interface is flawed.

I also thought along these lines. This is what gcc does:

sscanf("", "%d%d%d", &x, &y, &z);
printf("%d %d %d\n", x, y, z);
=> 0 1 1073787888

sscanf("1", "%d%d%d", &x, &y, &z);
printf("%d %d %d\n", x, y, z);
=> 1 1 1073787888

sscanf("12", "%d%d%d", &x, &y, &z);
printf("%d %d %d\n", x, y, z);
=> 12 1 1073787888

sscanf("123", "%d%d%d", &x, &y, &z);
printf("%d %d %d\n", x, y, z);
=> 123 1 1073787888

sscanf("123456", "%d%d%d", &x, &y, &z);
printf("%d %d %d\n", x, y, z);
=> 123456 1 1073787888

The analogous thing in Lisp with SETF of FORMAT should signal errors.

Christopher

Guy Footring

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Sam Steingold <s...@goems.com> writes:

>
> >>>> In message <87zp31c...@pc-hrvoje.srce.hr>
> >>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
> >>>> Sent on 19 May 1999 17:05:18 +0200
> >>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
> >> Sam Steingold <s...@goems.com> writes:
> >> > >>>> Honorable Hrvoje Niksic <hni...@srce.hr> writes:
> >> > >> strings such as "2+3i",
> >> > oh please! "2+3i" is a complex number while "2+3j" is a symbol.
> >>
> >> "2+3j" is not a symbol here because we're talking about a
> >> hypothetical PARSE-NUMBER, not about the Lisp reader. Anyway, you
>

[...]


>
> >> > >> "2 + 3i" as complex numbers.
> >> > so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?
> >> The latter.
>
> why? you mean `parse-number' will return something different from
> `parse-integer'?
>

What about 1.23? You mean parse-number WON'T return something different from
parse-integer??

Sam Steingold

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
>>>> In message <wtwvy4m...@thcsv01.trafford.ford.com>

>>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
>>>> Sent on 20 May 1999 09:21:15 +0100

>>>> Honorable Guy Footring <foot...@thcsv01.trafford.ford.com> writes:
>> Sam Steingold <s...@goems.com> writes:
>> >
>> > >> > >> "2 + 3i" as complex numbers.
>> > >> > so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?
>> > >> The latter.
>> >
>> > why? you mean `parse-number' will return something different from
>> > `parse-integer'?
>>
>> What about 1.23? You mean parse-number WON'T return something
>> different from parse-integer??

Sorry, I should have been more specific.

when both `parse-integer' and `parse-number' return, they should return
the same number. when `parse-number' returns a non-integer,
`parse-integer' should signal an error.

--
Sam Steingold (http://www.goems.com/~sds) running RedHat6.0 GNU/Linux
Micros**t is not the answer. Micros**t is a question, and the answer is Linux,
(http://www.linux.org) the choice of the GNU (http://www.gnu.org) generation.

NY survival guide: when crossing a street, mind cars, not streetlights.

Guy Footring

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Sam Steingold <s...@goems.com> writes:

>
> >>>> In message <wtwvy4m...@thcsv01.trafford.ford.com>
> >>>> On the subject of "Re: READ-FROM-STRING considered unsafe? (was Re: Simple Function Question)"
> >>>> Sent on 20 May 1999 09:21:15 +0100
> >>>> Honorable Guy Footring <foot...@thcsv01.trafford.ford.com> writes:
> >> Sam Steingold <s...@goems.com> writes:
> >> >
> >> > >> > >> "2 + 3i" as complex numbers.
> >> > >> > so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?
> >> > >> The latter.
> >> >
> >> > why? you mean `parse-number' will return something different from
> >> > `parse-integer'?
> >>
> >> What about 1.23? You mean parse-number WON'T return something
> >> different from parse-integer??
>
> Sorry, I should have been more specific.
>
> when both `parse-integer' and `parse-number' return, they should return
> the same number. when `parse-number' returns a non-integer,
> `parse-integer' should signal an error.
>

Both (parse-integer "1 + 2i") and (parse-integer "1.23") raise an
error unless :junk-allowed T is specified (at least under LWW4.1 ACL5.0 and an oldish
Lucid Unix release).

I don't see that there is a problem with
(parse-integer "1.23") => error
(parse-integer "1.23" :junk-allowed t) => 1
(parse-float "1.23") => 1.23s0 ;should parse-float take a float type specifier?
(parse-number "1.23") => 1.23s0
(parse-integer "1 + 3i") => error
(parse-integer "1 + 3i" :junk-allowed t) => 1
(parse-float "1 + 3i") => error
(parse-float "1 + 3i" :junk-allowed t) => error? 1.0s0?
(parse-number "1 + 3i") => #C(1 3)

Erik Naggum

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
* cba...@2xtreme.net (Christopher R. Barry)

| The analogous thing in Lisp with SETF of FORMAT should signal errors.

FYI, SSCANF returns the number of objects successfully assigned. if you
use the previous value of unassigned variables, it's your own problem.

BTW, I'd much prefer a binding form than a setting form, complete with
&OPTIONAL and &REST and all, like DESTRUCTURING-BIND.

#:Erik
--
@1999-07-22T00:37:33Z -- pi billion seconds since the turn of the century

Barry Margolin

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
In article <31362107...@naggum.no>, Erik Naggum <er...@naggum.no> wrote:
>* cba...@2xtreme.net (Christopher R. Barry)
>| The analogous thing in Lisp with SETF of FORMAT should signal errors.
>
> FYI, SSCANF returns the number of objects successfully assigned. if you
> use the previous value of unassigned variables, it's your own problem.
>
> BTW, I'd much prefer a binding form than a setting form, complete with
> &OPTIONAL and &REST and all, like DESTRUCTURING-BIND.
>
>#:Erik

If it weren't done using the SETF syntax (which I also don't really care
for -- its only virtue is "coolness factor"), I would probably just use a
function that returns each of the parsed items as multiple values, which
could be bound using MULTIPLE-VALUE-BIND:

(with-input-from-string (s "123 abcde 10")
(multiple-value-bind (a b c)
(parse-formatted "~d ~s ~o" s)
(list a b c))) =>
(123 ABCDE 8)

Christopher R. Barry

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Erik Naggum <er...@naggum.no> writes:

> BTW, I'd much prefer a binding form than a setting form, complete with
> &OPTIONAL and &REST and all, like DESTRUCTURING-BIND.

How would the filter be specified? What is your idea of that this
would look like?

(format-bind <lambda list>
<string-with-format-controls>
<string>
<implicit-progn>)

(format-bind (a b)
"~R"
"one hundred fifty-three"
(list a b))
==> Error: insufficient arguments error occurred when associating a value
with B

(format-bind (a &optional b)
"~R"
"one hundred fifty-three"
(list a b))
==> (153 nil)

(format-bind (a b c)
"~D~D~D"
"123456"
(list a b c))
==> Error: insufficient arguments error occurred when associating a value
with B
or
==> (123456 nil nil)
or something else???

?

Christopher

Hrvoje Niksic

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Guy Footring <foot...@thcsv01.trafford.ford.com> writes:

> I don't see that there is a problem with
> (parse-integer "1.23") => error
> (parse-integer "1.23" :junk-allowed t) => 1
> (parse-float "1.23") => 1.23s0 ;should parse-float take a float type specifier?
> (parse-number "1.23") => 1.23s0

Note that the whole point of introducing PARSE-NUMBER is to remove the
need for a PARSE-FLOAT.

Hrvoje Niksic

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
Sam Steingold <s...@goems.com> writes:

> >> could also allow "2+3j", for all I care.
>

> what about "2i"? "2i+3"? "2i+4j"?

I imagine that the last could be an error, if you insist -- and so
would be "2 + 3". Why are you asking me all this?

> >> too far into this discussion -- it's not like I have any idea why
> >> 2+3i would be any worse than 2+3j.
>
> what about "2+3k"?

Is "k" used somewhere to denote the imaginary part of a complex
number? How frequent is it?

> >> > >> "2 + 3i" as complex numbers.
> >> > so, what should (parse-number "2 + 3i") return? 2? or #C(2 3)?
> >> The latter.
>
> why? you mean `parse-number' will return something different from
> `parse-integer'?

Yes. (parse-integer "2 + 3i") signals an error, at least in CLISP and
CMU CL, where I tried it.

Hrvoje Niksic

unread,
May 20, 1999, 3:00:00 AM5/20/99
to
cba...@2xtreme.net (Christopher R. Barry) writes:

> I also thought along these lines. This is what gcc does:

[...]

Gcc?! You mean the C library on your system?

Kent M Pitman

unread,
May 21, 1999, 3:00:00 AM5/21/99
to
Hrvoje Niksic <hni...@srce.hr> writes:

But the whole point of introducing PARSE-FLOAT is to do what standards do
best: to publish what with certainty all implementations already have.

The problem with PARSE-NUMBER is that it is, as described, almost
certainly something no implementation presently has or needs, and for
any given choice of textual representation of complexes it will likely
satisfy only part of the community that thinks it wants a PARSE-NUMBER.
(Sort of the way any specific religion like Catholicism or Protestantism or
Judaism will satisfy only some subset of the people who think that
religion should be taught in school because people always
overoptimistically assume that when they ask for a cool thing under a
general name that it will do the specifics in a way that is not only
not general but that is fortuitously what suits them personally... so while
all of Jews and Catholics and Protestants might sign letters to Congress
saying they want religion in schools, many would end up also later signing
letters saying "get that OTHER religion out of schools" if anyone ever
took their proposal seriously.) I think people only want PARSE-NUMBER
because they imagine they would all be able to agree on a semantics or
that it doesn't matter to them that others won't like their choice because
they're assuming they won't be in the set that gets the version they
don't like. In practice, if PARSE-NUMBER parses floats and there is no
PARSE-FLOAT, then people will be having to do contorted things to screen
out representations they don't want (like rationals or complexes) and to
reformat other representations they want to be more palatable to PARSE-NUMBER.
I'd rather just give them building-blocks of PARSE-INTEGER and PARSE-FLOAT
because those are surely in the implementation anyway and then
let them build up anything application-specific that they need beyond that.

Philip Lijnzaad

unread,
May 21, 1999, 3:00:00 AM5/21/99
to

> sscanf("123456", "%d%d%d", &x, &y, &z);
> printf("%d %d %d\n", x, y, z);
> => 123456 1 1073787888

sscanf allows you to specify a maximum field width too:

sscanf("123456789", "%2d %3d 4%d", &x, &y, &z);


printf("%d %d %d\n", x, y, z);

12 345 6789

whereas

sscanf("123456789", "%4d %3d %2d", &x, &y, &z);


printf("%d %d %d\n", x, y, z);

1234 567 89.

The number between the '%' and 'd' is the maximum length to scan, but the
scan stops earlier if a non-digit is found. Also, scan always skips any white
space before it starts reading the next number. All a bit of a mess, really,
and not idempotent (which is what you'd like).

Incidentally, whitespace in the scan format is not significant,
strangely. But this is not comp.lang.c. So, anyway, I suppose that for (setf
(format ...) ...) you could also use the field widths of the format
specifiers, to get over the problem of (setf (format nil "~D~D" x y) "123")
(which I think should just make x 123 and y nil).
Philip

--
The mail transport agent is not liable for any coffee stains in this message
-----------------------------------------------------------------------------
Philip Lijnzaad, lijn...@ebi.ac.uk | European Bioinformatics Institute
+44 (0)1223 49 4639 | Wellcome Trust Genome Campus, Hinxton
+44 (0)1223 49 4468 (fax) | Cambridgeshire CB10 1SD, GREAT BRITAIN
PGP fingerprint: E1 03 BF 80 94 61 B6 FC 50 3D 1F 64 40 75 FB 53

Johan Kullstam

unread,
May 21, 1999, 3:00:00 AM5/21/99
to
Hrvoje Niksic <hni...@srce.hr> writes:

> Guy Footring <foot...@thcsv01.trafford.ford.com> writes:
>
> > I don't see that there is a problem with
> > (parse-integer "1.23") => error
> > (parse-integer "1.23" :junk-allowed t) => 1
> > (parse-float "1.23") => 1.23s0 ;should parse-float take a float type specifier?
> > (parse-number "1.23") => 1.23s0
>
> Note that the whole point of introducing PARSE-NUMBER is to remove the
> need for a PARSE-FLOAT.

just because you have a PARSE-NUMBER doesn't mean PARSE-FLOAT
PARSE-SINGLE-FLOAT, PARSE-DOUBLE-FLOAT PARSE-COMPLEX &c shouldn't
exist. having the specific forms may be useful in declaring what
exactly you mean.

PARSE-NUMBER may be implemented as a wrapper for the specific
instances. how about requiring a type in addition to the string?

(PARSE-NUMBER 'DOUBLE-FLOAT "2.718281828")
2.7183d0

(PARSE-NUMBER 'INTEGER "415")
415

a fancier implementation could default to infering the type (much as
the reader does), i.e., 1 is an integer, 1/2 is a rational, 1s3 is a
single-float &c, and take a :type key argument to allow you to
specify.

--
johan kullstam

Marco Antoniotti

unread,
May 24, 1999, 3:00:00 AM5/24/99
to

Johan Kullstam <kull...@ne.mediaone.net> writes:

> Hrvoje Niksic <hni...@srce.hr> writes:
>
> > Guy Footring <foot...@thcsv01.trafford.ford.com> writes:
> >
> > > I don't see that there is a problem with
> > > (parse-integer "1.23") => error
> > > (parse-integer "1.23" :junk-allowed t) => 1
> > > (parse-float "1.23") => 1.23s0 ;should parse-float take a float type specifier?
> > > (parse-number "1.23") => 1.23s0
> >
> > Note that the whole point of introducing PARSE-NUMBER is to remove the
> > need for a PARSE-FLOAT.
>
> just because you have a PARSE-NUMBER doesn't mean PARSE-FLOAT
> PARSE-SINGLE-FLOAT, PARSE-DOUBLE-FLOAT PARSE-COMPLEX &c shouldn't
> exist. having the specific forms may be useful in declaring what
> exactly you mean.
>
> PARSE-NUMBER may be implemented as a wrapper for the specific
> instances. how about requiring a type in addition to the string?
>
> (PARSE-NUMBER 'DOUBLE-FLOAT "2.718281828")
> 2.7183d0

(PARSE-NUMBER "2.718281828" :type 'double-float)

Would be better. Contrary to CONCATENATE there is no &rest argument
to deal with. However what would you do with

(PARSE-NUMBER "2" :type 'NUMBER)

?

Cheers

Juanma Barranquero

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 24 May 1999 11:33:44 +0200, Marco Antoniotti
<mar...@copernico.parades.rm.cnr.it> wrote:

>However what would you do with
>
>(PARSE-NUMBER "2" :type 'NUMBER)
>
>?

Return a number of the type (type-of 2) would return in the given
implementation. In my system (and most of them, I'd expect), a FIXNUM.
And

(parse-number "536870912" :type 'number)

would return a BIGNUM because (type-of 536870912) says it is a BIGNUM
(again, in my ACL).

/L/e/k/t/u

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0kabP4C0a0jUw5YEQJ61wCgyQIZpWCRF4AvbCq3ory6hOoD8jMAnA5r
wroYDlptMC1CuJpGLW/B8HCd
=Ds/C
-----END PGP SIGNATURE-----


Marco Antoniotti

unread,
May 24, 1999, 3:00:00 AM5/24/99
to

barra...@laley-actualidad.es (Juanma Barranquero) writes:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 24 May 1999 11:33:44 +0200, Marco Antoniotti
> <mar...@copernico.parades.rm.cnr.it> wrote:
>
> >However what would you do with
> >
> >(PARSE-NUMBER "2" :type 'NUMBER)
> >
> >?
>
> Return a number of the type (type-of 2) would return in the given
> implementation. In my system (and most of them, I'd expect), a FIXNUM.
> And
>
> (parse-number "536870912" :type 'number)
>
> would return a BIGNUM because (type-of 536870912) says it is a BIGNUM
> (again, in my ACL).
>


Therefore,

(PARSE-NUMBER "12" :type 'bignum)

should signa an error, shouldn't it?

Juanma Barranquero

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

>Therefore,


>
>(PARSE-NUMBER "12" :type 'bignum)
>
>should signa an error, shouldn't it?

Yes.

I think a reasonable behavior for

(parse-number NUMBER-AS-STRING :type 'TYPE)

could be as follows:

Let's define N as (read-from-string NUMBER-AS-STRING) and TN as
(type-of N).

Then, if (subtypep TN TYPE) == t, the number returned would be N of
type TN; else parse-number should signal an error (or return nil, or
whatever).

You cannot force N to be of type TYPE unless is possible to have
objects for which (type-of OBJECT) == TYPE. Since BIGNUM and FIXNUM
are an exhaustive partition of INTEGER, I suppose (perhaps I'm wrong)
that if N is an INTEGER, an implementation will return BIGNUM or
FIXNUM for (type-of N), and not INTEGER, so

(parse-number N :type 'INTEGER)

should return either a FIXNUM or a BIGNUM as appropriate.

So if someone wants to parse an INTEGER with parse-number, he should
use :type 'INTEGER. Using :type 'BIGNUM should be a promise that
*really* a BIGNUM is expected.

A problem: May seem counter-intuitive to have

(parse-number "1.0" :type 'DOUBLE-FLOAT)

to return an error, but (typep 1.0 'DOUBLE-FLOAT) is nil, so is not
totally illogical. Hmmm...

/L/e/k/t/u

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0lKW/4C0a0jUw5YEQK3mwCgwSAA8ZcLc045U20JU35P5fE39DgAoMJL
aWkfz3fibp4zVfYQOmdu3E7h
=S+cx
-----END PGP SIGNATURE-----


Barry Margolin

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
In article <37514102....@news.mad.ttd.net>,

Juanma Barranquero <barra...@laley-actualidad.es> wrote:
>A problem: May seem counter-intuitive to have
>
>(parse-number "1.0" :type 'DOUBLE-FLOAT)
>
>to return an error, but (typep 1.0 'DOUBLE-FLOAT) is nil, so is not
>totally illogical. Hmmm...

Not illogical, but it seems counter to what PARSE-NUMBER seems to be
intended for. I thought we were discussing a function that could be used
to parse data that isn't necessarily from a Lisp source, e.g. a user. We
may want to read in a float, but does that mean that a user who is totally
unfamiliar with Lisp should be expected to know that floats have to have an
embedded decimal point? It would seem more useful, in this context, to
have

(parse-number S :type T)

perform something similar to

(coerce (read-from-string S) T)

Christopher R. Barry

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
barra...@laley-actualidad.es (Juanma Barranquero) writes:

[...]

> (parse-number "1.0" :type 'DOUBLE-FLOAT)
>
> to return an error, but (typep 1.0 'DOUBLE-FLOAT) is nil, so is not
> totally illogical. Hmmm...

If you want 1.0 to be read as a DOUBLE-FLOAT, then you write it as
1.0d0. You could have also tried (COERCE 1.0 'DOUBLE-FLOAT) =>
1.0d0. You should be able to parse floats as any subtype of FLOAT that
you wish, even allowing truncation, since you can do

USER(8): pi
=> 3.141592653589793d0

USER(9): (coerce pi 'single-float)
=> 3.1415927

Christopher

Johan Kullstam

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
Marco Antoniotti <mar...@copernico.parades.rm.cnr.it> writes:

> Johan Kullstam <kull...@ne.mediaone.net> writes:
>
> > Hrvoje Niksic <hni...@srce.hr> writes:
> >
> > > Guy Footring <foot...@thcsv01.trafford.ford.com> writes:
> > >
> > > > I don't see that there is a problem with
> > > > (parse-integer "1.23") => error
> > > > (parse-integer "1.23" :junk-allowed t) => 1
> > > > (parse-float "1.23") => 1.23s0 ;should parse-float take a float type specifier?
> > > > (parse-number "1.23") => 1.23s0
> > >
> > > Note that the whole point of introducing PARSE-NUMBER is to remove the
> > > need for a PARSE-FLOAT.
> >
> > just because you have a PARSE-NUMBER doesn't mean PARSE-FLOAT
> > PARSE-SINGLE-FLOAT, PARSE-DOUBLE-FLOAT PARSE-COMPLEX &c shouldn't
> > exist. having the specific forms may be useful in declaring what
> > exactly you mean.
> >
> > PARSE-NUMBER may be implemented as a wrapper for the specific
> > instances. how about requiring a type in addition to the string?
> >
> > (PARSE-NUMBER 'DOUBLE-FLOAT "2.718281828")
> > 2.7183d0
>
> (PARSE-NUMBER "2.718281828" :type 'double-float)

> Would be better. Contrary to CONCATENATE there is no &rest argument

> to deal with. However what would you do with

yes. this reads better.

> (PARSE-NUMBER "2" :type 'NUMBER)

well, anything that would be a number equal to two, i think it would
be ok. so as long as

(setq x (parse-number "2" :type 'number))

(and (numberp x) (= x 2))

returns t, i would be happy.

thus 2 or 2d0 could be valid values.

i think using the most specific type possible for the return would be
best. hence i might be surprised if i didn't get a fixnum in the
above case.

if you want a more specific answer, it would behoove you to be more
specific!

* * *

the general reading problem, as i see it, is this:

in printing from lisp, you have lots of information such as the type.
therefore format can make do with things like ~A which work with most
anything.

when you read, you have no idea what you're reading. the type
information needs to be inferred from syntax (like the full
lisp-reader) or supplied from somewhere else (like parse-integer
explicitly calls out integer).

in light of the asymmetry of knowledge wrt to type information,
something like

(setf x (format "2" "~A"))

has no hope of working.

C has no idea what type anything is in. you have to explicitly supply
types in the format string in both input and output cases. therefore
printf and scanf format strings look (mostly) the same.[1]

since this problem is not limited to numbers, how would one go about
reading some arbitrary type such as a vector or structure? perhaps we
should say nothing about hash-tables.

[1] C cannot pass floats, only doubles hence both floats and doubles
are printed with %f but scanned with %f and %lf respectively.

--
johan kullstam

Juanma Barranquero

unread,
May 24, 1999, 3:00:00 AM5/24/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On Mon, 24 May 1999 15:05:00 GMT, Barry Margolin
<bar...@bbnplanet.com> wrote:

>I thought we were discussing a function that could be used
>to parse data that isn't necessarily from a Lisp source, e.g. a user.

Then

(parse-number "1.0" :type 'FLOAT)

will do (or 'REAL, 'NUMBER). Use as general a type as needed. I
assumed :type 'BIGNUM or 'DOUBLE-FLOAT or other more specific types
would be used for reading data where we *know for sure* what's being
read (not from the user, but from a C-generated file, for example). I
see no contradiction.

>We may want to read in a float, but does that mean that a user who is
>totally unfamiliar with Lisp should be expected to know that floats
>have to have an embedded decimal point?

Then (float (parse-number NUMBER-AS-STRING :type 'REAL) 1.0d0) and
check for errors.

>It would seem more useful, in this context, to have
>
>(parse-number S :type T)
>
>perform something similar to
>
>(coerce (read-from-string S) T)

What you're proposing is not very different of what I've suggested in
my previous post, I think. I suppose you say "something similar to"
because of that:

USER(56): (coerce (read-from-string "1") 'bignum)
Error: Can't coerce 1 to type BIGNUM.
[condition type: SIMPLE-ERROR]


so in fact, as Marco Antoniotti pointed to me, if you want generality
at read time, you're *forced* to ask for a more general type and
coerce to (type-of N), i.e., a subtype of T and not T.

That's why I said that parse-number *cannot* always return the asked
for type, but only a subtype of it. As I see it, it's a no-win
situation. There are two sensible ways to define the return value of:

(parse-number N-AS-S :type T)

1.- You expect parse-number to coerce the number to T (with an error
if it cannot deliver, as in the BIGNUM example), or

2.- parse-number returns a number of the most appropriate subtype of
T, and you manually coerce the number and/or check for errors (as in
the 'REAL example above) if needed.

I prefer the second alternative.


/L/e/k/t/u

P.S.: Sorry if I'm not being very intelligible; I've rewritten this
message a couple times, but my English is failing me miserably :(

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0lmRv4C0a0jUw5YEQJixQCfeg0xK3Jk4qApW+yLI5wcxcIjXQoAn3Qf
JtixIp73HMBGNQGLgkyXRQjv
=ZHXQ
-----END PGP SIGNATURE-----


Tim Bradshaw

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
* Juanma Barranquero wrote:

> (parse-number "1.0" :type 'DOUBLE-FLOAT)

> to return an error, but (typep 1.0 'DOUBLE-FLOAT) is nil, so is not
> totally illogical. Hmmm...

* (type-of 1.0)
double-float

* *read-default-float-format*
double-float

PARSE-FLOAT is so much easier.

Tim Bradshaw

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
* Christopher R Barry wrote:
> You should be able to parse floats as any subtype of FLOAT that
> you wish, even allowing truncation, since you can do

Yes, the thing is useless unless it can read 1.0 as any kind of float
you like, otherwise you lose precision parsing "1.003984759478985" I'm
not *sure* it's useless unless it can read "1" as a float too, I'd
certainly like it to be able to if it existed, to save having to wrap
all my calls to it by a COERCE.

--tim

Juanma Barranquero

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 25 May 1999 00:09:35 +0100, Tim Bradshaw <t...@tfeb.org> wrote:

>* *read-default-float-format*
>double-float

Well, you're right. Still, that only means that an hypothetical
parse-number would have to take *read-default-float-format* into
account (or bind it to the default 'single-float).

What I thought we were discussing is how to determine if parse-number
can be designed so its working is fully specified, logical (and/or
intuitive) *and* useful. I think we've already determined it's not so
trivial a function as to not be worth including in the standard; at
least is far less trivial to implement than parse-integer.

So far, the problem is not if parse-number can read a float or not,
but what to do when the data input and the asked-for type are in
conflict. If the programmer has bound/set *read-default-float-format*
to 'double-float and then he does

(parse-number "1.0" :type 'single-float)

what kind of error is that? A bug in the working (or specification) of
parse-number, or a programmer error? I'd say the later. And anyway,
for user input, as it's been said in earlier messages, it seems a lot
less error prone to use more generic number types (FLOAT, REAL,
INTEGER) and then coerce the result.

>PARSE-FLOAT is so much easier.

The parse-number we're discussing could act as a parse-integer,
parse-rational, parse-float, parse-real and *still* have more
specialized uses (with more specialized :type parameters). I
definitively see it as very useful.

/L/e/k/t/u


-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0pG/f4C0a0jUw5YEQJxgACfbQk0F1kL+bTisSgR6LXYFEftRhcAoJFK
D6LN+vnJHsh1DyVNLPFrCICx
=NxWK
-----END PGP SIGNATURE-----


Erik Naggum

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
* barra...@laley-actualidad.es (Juanma Barranquero)

| What you're proposing is not very different of what I've suggested in
| my previous post, I think. I suppose you say "something similar to"
| because of that:
|
| USER(56): (coerce (read-from-string "1") 'bignum)
| Error: Can't coerce 1 to type BIGNUM.
| [condition type: SIMPLE-ERROR]

pardon me, but why this obsession with bignums and fixnums? like all
types, they do partition a value space, but in a different way than most
types. you can have the numeric value 1 in any numeric type, but the
implementation artifact of machine integers means it cannot be a bignum
(unless you allow unnormalized bignums, but I digress). whether an
integer is a bignum or a fixnum should be none of your concern (unless
you have severe performance constraints, but I digress).

I think you will find the answer sooner (whatever it is you're seeking)
if you don't trouble yourself with such things.

FWIW, I would like to know the object type of the object that would most
likely be created if READ (etc) were applied to a string. (that's "most
likely" because I don't want error handling until I actually want the
object, and I don't want to go ahead and read the string with all the
attendant side effects until I'm sure I want the result. error handling
is great, but it necessarily happens after the error has occurred, and
that is not sufficient at all times.)

Erik Naggum

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
* Johan Kullstam <kull...@ne.mediaone.net>

| [1] C cannot pass floats, only doubles hence both floats and doubles
| are printed with %f but scanned with %f and %lf respectively.

FWIW, this is no longer true. ANSI C, published a decade ago, specified
that if the prototype is in scope, a function call should coerce an
argument to the appropriate numeric type, including short, float, etc,
and the function can expect the object to have the specified type. if
the prototype is not in scope, certain defaults apply that should cause
an error to be reported when a conflicting prototype is seen.

the reason C cannot do %f as anything but double is that there is no
prototype for printf (etc) that could request any particular type, hence
the default conversions apply.

Juanma Barranquero

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 25 May 1999 13:03:13 +0000, Erik Naggum <er...@naggum.no> wrote:

> pardon me, but why this obsession with bignums and fixnums? like
> all types, they do partition a value space, but in a different way
> than most types. you can have the numeric value 1 in any numeric
> type, but the implementation artifact of machine integers means it
> cannot be a bignum (unless you allow unnormalized bignums, but I
> digress). whether an integer is a bignum or a fixnum should be
> none of your concern (unless you have severe performance
> constraints, but I digress).

I have no obsession with bignums and fixnums. I am merely stating
that, were parse-number to be defined with a type parameter (like
Johan Kullstam proposed, not me), Marco Antoniotti's concern about the
behavior of

(parse-number "2" :type 'number)

is also valid with respect to the case when :type is a bignum, fixnum,
rational, single-float, etc. and that the type of parse-number's
result *cannot* be expected to be exactly the type T specified to
parse-number, but only a subtype of it. That's all I'm saying (well,
I'm also saying I still find parse-number to be potentially useful).

> FWIW, I would like to know the object type of the object that would
> most likely be created if READ (etc) were applied to a string.

That's fine by me.

/L/e/k/t/u

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0q1Ev4C0a0jUw5YEQKgVQCg3GbjjzqwDxx4W2sQb+xzQqQJbkwAn0eQ
QUzJyefk53UuZ9ITYBHyJ+jh
=fEG5
-----END PGP SIGNATURE-----


Tim Bradshaw

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
* Juanma Barranquero wrote:
> -----BEGIN PGP SIGNED MESSAGE-----

> So far, the problem is not if parse-number can read a float or not,
> but what to do when the data input and the asked-for type are in
> conflict. If the programmer has bound/set *read-default-float-format*
> to 'double-float and then he does

> (parse-number "1.0" :type 'single-float)

> what kind of error is that? A bug in the working (or specification) of
> parse-number, or a programmer error? I'd say the later. And anyway,
> for user input, as it's been said in earlier messages,

Half the point of the wretched thing is that it should be a
*function*, something that returns a result dependent on its
arguments, not on some obscure set of global variables.

It should also, I think, (as Kent Pitman pointed out) expose
functionality that is required in an implementation anyway, which is
what PARSE-FLOAT does, and PARSE-NUMBER does not do.

--tim

Christopher R. Barry

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
Erik Naggum <er...@naggum.no> writes:

> FWIW, I would like to know the object type of the object that would most

> likely be created if READ (etc) were applied to a string. (that's "most
> likely" because I don't want error handling until I actually want the
> object, and I don't want to go ahead and read the string with all the
> attendant side effects until I'm sure I want the result.

Something like PEEK-READ and PEEK-READ-FROM-STRING

(peek-read-from-string "1/0")
=> #<DIVISION-BY-ZERO>

> error handling is great, but it necessarily happens after the
> error has occurred, and that is not sufficient at all times.

Cases like

(ignore-errors
(read-from-string
"(arbitrary-function-call-invoking-massive-global-state-change)"))

come to mind. Setting up an UNWIND-PROTECT form to deal with every
error you might encounter in a rational way is just impossible.... How
would you work out the details of this though?

(peek-read-from-string
"(arbitrary-function-call-invoking-massive-global-state-change)")
=> #<FUNCTION ARBITRARY-FUNCTION-CALL-INVOKING-MASSIVE-GLOBAL-STATE-CHANGE>

But if you wanted access to the function's arguments would you then
manually parse the string for them or would you want
PEEK-READ-FROM-STRING to have some way of doing this to? If the
former, then this doesn't seem _much_ better than parsing a "(...)"
form and testing the CAR for FDEFINITION to see if it's a
#<FUNCTION...> anyways.

Anyways, yes, CL needs at least a simple facility for doing this.

Christopher

Juanma Barranquero

unread,
May 25, 1999, 3:00:00 AM5/25/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 25 May 1999 18:11:43 +0100, Tim Bradshaw <t...@tfeb.org> wrote:

>Half the point of the wretched thing is that it should be a
>*function*, something that returns a result dependent on its
>arguments, not on some obscure set of global variables.

Well, we're discussing how should it work, so maybe that's a better
solution (not depending of *read-default-float-format*, I mean). Let's
not forget that parse-integer has a :radix keyword parameter and does
not depend on the value of *read-base*.

>It should also, I think, (as Kent Pitman pointed out) expose
>functionality that is required in an implementation anyway, which
>is what PARSE-FLOAT does, and PARSE-NUMBER does not do.

Perhaps that's the better way, but I feel that, either parse-float
ends being very similar to parse-number (accepting integer values and
coercing them to floats, etc.), or the programmers will have to
implement their own parse-number with parse-{integer,float} for
reading user-supplied values and the like.

/L/e/k/t/u

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0r9Mv4C0a0jUw5YEQKWKwCeKQykinGxs0yFkq6So/0kUmcEKjQAmwUF
eAgMAEzV1J9S4gAwlqw5zHY1
=iCOH
-----END PGP SIGNATURE-----


Erik Naggum

unread,
May 26, 1999, 3:00:00 AM5/26/99
to
* Erik Naggum <er...@naggum.no>

| FWIW, I would like to know the object type of the object that would most
| likely be created if READ (etc) were applied to a string. (that's "most
| likely" because I don't want error handling until I actually want the
| object, and I don't want to go ahead and read the string with all the
| attendant side effects until I'm sure I want the result.

* Christopher R. Barry <cba...@2xtreme.net>


| Something like PEEK-READ and PEEK-READ-FROM-STRING
|
| (peek-read-from-string "1/0")
| => #<DIVISION-BY-ZERO>

no, nothing like that at all. let's call it PRETEND-READ. what I want
PRETEND-READ to return is the _type_ of the object READ would return, and
it should _not_ do error processing. I actually want to capture the
syntactic type of the object before it fails to get created.

| Cases like
|
| (ignore-errors
| (read-from-string
| "(arbitrary-function-call-invoking-massive-global-state-change)"))
|
| come to mind.

READ doesn't call EVAL voluntarily. and #. can be killed in two ways:
binding *READ-EVAL* to NIL, and nuking #\# #\. in the readtable.

| But if you wanted access to the function's arguments would you then
| manually parse the string for them or would you want
| PEEK-READ-FROM-STRING to have some way of doing this to?

I think you just need to evaluate the above example expression to see
what it actually returns.

| If the former, then this doesn't seem _much_ better than parsing a
| "(...)" form and testing the CAR for FDEFINITION to see if it's a
| #<FUNCTION...> anyways.

look, READ doesn't do _any_ magic with the forms it reads. READ converts
the string representation produced by WRITE into the internal form once
given to WRITE. that we write source code in like manner is no accident,
but looking up the _values_ of symbols is not what READ does.

it seems to me you're thinking in some over-simplified Scheme terms.

BTW, in order to sanely capture errors when reading random input, I do
some fairly complex shenanigans:

(defun safe-read-with-string (input)
"Read an expression off of INPUT. Return the parse value and the string.
If an error occurs, the error is returned in place of the value."
(with-open-stream (string (make-string-output-stream))
(with-open-stream (echo (make-echo-stream input string))
(handler-case
(let ((*read-suppress* t)
(*read-eval* nil))
(read-preserving-whitespace echo)
(values))
(error (error)
(values error (get-output-stream-string string)))
(:no-error ()
(let ((string (get-output-stream-string string)))
(handler-case
(values (read-from-string string) string)
(error (error)
(values error string)))))))))

this means I can easily capture the offending string, which I would
otherwise lose, and use it for error messages, and I can be ensured that
what has been read has been as complete an object as possible, as opposed
to when reading stops short in the middle of a list and it's non-trivial
to get yourself back on track unless you cop out and CLEAR-INPUT. ouch!

(that this function is also used to capture the string representation of
the object because the string representation is subject to MD5 checksums
only adds to its utility and does not detract from the principal problem.)

Tim Bradshaw

unread,
May 26, 1999, 3:00:00 AM5/26/99
to
* Juanma Barranquero wrote:

> Perhaps that's the better way, but I feel that, either parse-float
> ends being very similar to parse-number (accepting integer values and
> coercing them to floats, etc.), or the programmers will have to
> implement their own parse-number with parse-{integer,float} for
> reading user-supplied values and the like.

Well, the problem is that PARSE-NUMBER (if it is rightly named) needs
to deal with complexes and that's a huge nightmare. PARSE-REAL might
be better.

--tim

Juanma Barranquero

unread,
May 26, 1999, 3:00:00 AM5/26/99
to
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 26 May 1999 00:23:48 +0100, Tim Bradshaw <t...@tfeb.org> wrote:

>Well, the problem is that PARSE-NUMBER (if it is rightly named) needs
>to deal with complexes and that's a huge nightmare. PARSE-REAL might
>be better.

Yes, you're right. I read the comments by Sam Steingold about 2+3i,
2i+4j, etc. so I was very busy tiptoeing past the issue of complexes
:)

But still a parse-real would be good.

/L/e/k/t/u

-----BEGIN PGP SIGNATURE-----
Version: PGPfreeware 6.0.2i

iQA/AwUBN0xbBv4C0a0jUw5YEQICDACeNmNx5L+9SS0JRLX0rWGF3O4xgXQAn0eQ
KE3xZnJKng7vCZd2bAaPt4qX
=f51U
-----END PGP SIGNATURE-----


0 new messages