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

Small read macro issue

31 views
Skip to first unread message

Adam Warner

unread,
Oct 6, 2002, 1:33:19 AM10/6/02
to
Hi all,

I'm just a little stuck on how to turn this syntax:

(function-name[some text]"more text")

Into this syntax:

(function-name :options "[some text]" "more text")

This allows me to distinguish whether an initial optional string has been
input. Otherwise there is no way to distinguish between these situations:

(function-name "options" "text1" "text2" ...)
(function-name "text1" "text2" ...)

(Note: I am unaware of any way to attach a particular type to the initial
optional string so that it can be tested for as different to a regular
string).

This is the best I can do so far:


(set-macro-character
#\[ #'(lambda (in-stream char)
(declare (ignore char))
(let ((text-string (with-output-to-string (out-stream)
(write-char #\[ out-stream)
(loop for char = (read-char in-stream)
until (char= char #\])
do (write-char char out-stream))
(write-char #\] out-stream))))
`(list :options ,text-string))))


Which leads to this example output:

'(function-name[some text]"more text")
(FUNCTION-NAME (LIST :OPTIONS "[some text]") "more text")

It's usable but the nested list is not required.

I have also tried values and read-from-string to try and return two
separate objects but I get the error message "macro character definition
for #\[ may not return 2 values, only one value."

So it doesn't seem possible to get exactly the result I am looking for (but
I thought I'd quickly check with you all).

Thanks,
Adam

Vassil Nikolov

unread,
Oct 6, 2002, 2:15:50 AM10/6/02
to
On Sat, 05 Oct 2002 18:33:19 -1100, "Adam Warner" <use...@consulting.net.nz> said:

AW> Hi all,
AW> I'm just a little stuck on how to turn this syntax:

AW> (function-name[some text]"more text")

AW> Into this syntax:

AW> (function-name :options "[some text]" "more text")

Common Lisp doesn't have `splicing read macros' so there isn't a
straightforward way to achieve that.

I wonder if it makes sense for you to revise the syntax.

As one approach, if you use your own macro characters instead of
parentheses to enclose the whole form, then the read macro for the
opening one would read the function name and the optional text and
cons these (without a nested list) in front of what
READ-DELIMITED-LIST would return for the input after the closing
bracket.

---Vassil.

--
Garbage collection is charged at 0.19e-9 cents a cons. Bulk rates
are also available: please contact memory management for details.

Adam Warner

unread,
Oct 6, 2002, 3:02:08 AM10/6/02
to
Hi Vassil Nikolov,

> AW> Hi all,
> AW> I'm just a little stuck on how to turn this syntax:
>
> AW> (function-name[some text]"more text")
>
> AW> Into this syntax:
>
> AW> (function-name :options "[some text]" "more text")
>
> Common Lisp doesn't have `splicing read macros' so there isn't a
> straightforward way to achieve that.

Thanks for putting a name to the missing functionality.

> I wonder if it makes sense for you to revise the syntax.
>
> As one approach, if you use your own macro characters instead of
> parentheses to enclose the whole form, then the read macro for the
> opening one would read the function name and the optional text and cons
> these (without a nested list) in front of what READ-DELIMITED-LIST would
> return for the input after the closing bracket.

Thanks for the idea. I have just figured out an expensive way to achieve
the desired result: The [ read macro converts the string to a | | enclosed
symbol to maintain case (using read-from-string) and the function is then
able to distinguish between an optional symbol and a string. This kind of
approach would work with any object that is not a string.

(set-macro-character
#\[ #'(lambda (in-stream char)
(declare (ignore char))
(let ((text-string (with-output-to-string (out-stream)
(write-char #\[ out-stream)
(loop for char = (read-char in-stream)
until (char= char #\])
do (write-char char out-stream))
(write-char #\] out-stream))))

(first (list (read-from-string (concatenate 'string "|" text-string "|")))))))

'(function-name[some text]"more text")
(FUNCTION-NAME |[some text]| "more text")

I used (first (list ...)) to get rid of the second return value of
read-from-string. There is probably a better way that I am unaware of.

Regards,
Adam

Paul Foley

unread,
Oct 6, 2002, 4:20:50 AM10/6/02
to
On Sat, 05 Oct 2002 20:02:08 -1100, Adam Warner wrote:

> Thanks for the idea. I have just figured out an expensive way to achieve
> the desired result: The [ read macro converts the string to a | | enclosed
> symbol to maintain case (using read-from-string) and the function is then
> able to distinguish between an optional symbol and a string. This kind of
> approach would work with any object that is not a string.

> (set-macro-character
> #\[ #'(lambda (in-stream char)
> (declare (ignore char))
> (let ((text-string (with-output-to-string (out-stream)
> (write-char #\[ out-stream)
> (loop for char = (read-char in-stream)
> until (char= char #\])
> do (write-char char out-stream))
> (write-char #\] out-stream))))
> (first (list (read-from-string (concatenate 'string "|" text-string "|")))))))

(set-macro-character #\[
(lambda (stream char)
(declare (ignore char))
(intern (funcall (get-macro-character #\") stream #\]))))

> '(function-name[some text]"more text")
> (FUNCTION-NAME |[some text]| "more text")

> I used (first (list ...)) to get rid of the second return value of
> read-from-string. There is probably a better way that I am unaware of.

(values (read-from-string ...))

--
And ælc þara þe gehierð þas min word, and þa ne wyrcþ, se bið gelic þæm
dysigan menn...

(setq reply-to
(concatenate 'string "Paul Foley " "<mycroft" '(#\@) "actrix.gen.nz>"))

Kalle Olavi Niemitalo

unread,
Oct 6, 2002, 4:45:31 AM10/6/02
to
"Adam Warner" <use...@consulting.net.nz> writes:

> I have just figured out an expensive way to achieve the desired result:
> The [ read macro converts the string to a | | enclosed symbol to
> maintain case (using read-from-string) and the function is then able
> to distinguish between an optional symbol and a string.

That won't work if the original string contains | characters.
MAKE-SYMBOL or INTERN would not have this problem.

The nested list in your original article does not look too bad, either.
You also have the option of hiding the function behind a macro;
then you can have (macro-name[some text]"more text") read as
(macro-name (:options "[some text]") "more text"), which then expands
to (function-name :options "[some text]" "more text") at compile time.
Having both MACRO-NAME and FUNCTION-NAME could be confusing, though.

Alternatively, you could define a structure and have the reader macro wrap
the string in an instance of that. The structure would be self-evaluating
so it would not need a quote, and the function could easily recognize it
by type.

Adam Warner

unread,
Oct 6, 2002, 6:06:37 AM10/6/02
to
Hi Kalle Olavi Niemitalo,

>> I have just figured out an expensive way to achieve the desired result:
>> The [ read macro converts the string to a | | enclosed symbol to
>> maintain case (using read-from-string) and the function is then able to
>> distinguish between an optional symbol and a string.
>
> That won't work if the original string contains | characters.
> MAKE-SYMBOL or INTERN would not have this problem.

Oh! Thanks for the tip.



> The nested list in your original article does not look too bad, either.
> You also have the option of hiding the function behind a macro; then you
> can have (macro-name[some text]"more text") read as (macro-name
> (:options "[some text]") "more text"), which then expands to
> (function-name :options "[some text]" "more text") at compile time.
> Having both MACRO-NAME and FUNCTION-NAME could be confusing, though.

Alternatively the function could just flatten any lists. Then I would be
able to accept both syntaxes!

> Alternatively, you could define a structure and have the reader macro
> wrap the string in an instance of that. The structure would be
> self-evaluating so it would not need a quote, and the function could
> easily recognize it by type.

This is what I originally wanted to do. I wanted to attach a special type
to the string. Now I know how :-)

(defstruct opt options)
(type-of (make-opt :options "options text"))
OPT

This would work like a charm once the reader macro [options text] was
created to generate (make-opt :options "[options text]"). But it seems that
the longhand syntax would be worse: instead of being able to type :keyword
"text" I would have to turn the string into the OPT type using
make-opt, or type the printed representation #S(OPT :OPTIONS "options text")

Perhaps flattening any lists and accepting both syntaxes would be the best
way to proceed. Although the defstruct way seems very elegant.

The concept of a default structure might be nice:

(defstruct :set-default default x y z)

...would allow #S(:x "options text") etc. to be entered without having to
enter the name of the default structure (here called DEFAULT).

Thanks,
Adam

Kenny Tilton

unread,
Oct 6, 2002, 7:58:47 AM10/6/02
to

Adam Warner wrote:
> Hi all,
>
> I'm just a little stuck on how to turn this syntax:
>
> (function-name[some text]"more text")
>
> Into this syntax:
>
> (function-name :options "[some text]" "more text")
>
> This allows me to distinguish whether an initial optional string has been
> input. Otherwise there is no way to distinguish between these situations:
>
> (function-name "options" "text1" "text2" ...)
> (function-name "text1" "text2" ...)

Could you use a macro instead?

(defmacro macro-name (&optional some-text) &rest other-texts)
...etc)

Then the syntax would be:

(macro-name () "aaa" "bbb") or (macro-name ("some text") "aaa" "bbb")

kenny
clinisys

Vassil Nikolov

unread,
Oct 7, 2002, 12:10:55 AM10/7/02
to
On Sat, 05 Oct 2002 23:06:37 -1100, "Adam Warner" <use...@consulting.net.nz> said:

[...]
AW> This would work like a charm once the reader macro [options text] was
AW> created to generate (make-opt :options "[options text]"). But it seems that
AW> the longhand syntax would be worse: instead of being able to type :keyword
AW> "text" I would have to turn the string into the OPT type using
AW> make-opt, or type the printed representation #S(OPT :OPTIONS "options text")

[...]
AW> The concept of a default structure might be nice:

AW> (defstruct :set-default default x y z)

AW> ...would allow #S(:x "options text") etc. to be entered without having to
AW> enter the name of the default structure (here called DEFAULT).

Oh, no, redefining #S in this way is fraught with peril. And what
more would it give you (apart from headaches) than defining #\[ as
a character macro such that

[options text]

reads the same as

#S(opt :options "options text")

Just to make quite sure there is no misunderstanding, note that the
reader macro function associated with #\[ will return the value of
(MAKE-OPT :OPTIONS "options text"), rather than the list (MAKE-OPT
:OPTIONS "options text"). In other words, the expression producing
the return value of that function will be

(make-opt :options input-options-text)

rather than

`(make-opt :options ,input-options-text)

Erik Naggum

unread,
Oct 7, 2002, 9:46:15 AM10/7/02
to
* "Adam Warner" <use...@consulting.net.nz>

| I used (first (list ...)) to get rid of the second return value of
| read-from-string. There is probably a better way that I am unaware of.

Yes. Use nothing.

--
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.

Adam Warner

unread,
Oct 7, 2002, 10:41:56 AM10/7/02
to
Erik Naggum wrote:

> * "Adam Warner" <use...@consulting.net.nz>
> | I used (first (list ...)) to get rid of the second return value of
> | read-from-string. There is probably a better way that I am unaware of.
>
> Yes. Use nothing.

[1]> (set-macro-character #\[


#'(lambda (in-stream char)
(declare (ignore char))

(read-from-string "'(test)"))))
T
[2]> [

*** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
#<IO SYNONYM-STREAM *TERMINAL-IO*>>:


macro character definition for #\[ may not return 2 values, only one value.

1. Break [3]>

[4]> (set-macro-character #\[


#'(lambda (in-stream char)
(declare (ignore char))

(values (read-from-string "'(test)")))))
T
[5]> [
(TEST)

Attempting to create a splicing read macro was the whole point of the thread.

Erik Naggum

unread,
Oct 7, 2002, 11:50:56 AM10/7/02
to
* Adam Warner

| I'm just a little stuck on how to turn this syntax:
|
| (function-name[some text]"more text")
|
| Into this syntax:
|
| (function-name :options "[some text]" "more text")

That is the wrong goal.

| This allows me to distinguish whether an initial optional string has been
| input.

So you need a mechanism to distinguish them, not an answer to what you
are asking for.

| Otherwise there is no way to distinguish between these situations:
|
| (function-name "options" "text1" "text2" ...)
| (function-name "text1" "text2" ...)
|
| (Note: I am unaware of any way to attach a particular type to the initial
| optional string so that it can be tested for as different to a regular
| string).

A wrapper class. The solution is so close you have probably overlooked it.

(defclass warner-option ()
((option :type string :reader warner-option :initarg :option)))

;; useful for debugging
(defmethod print-object ((option warner-option) stream)
(print-unreadable-object (option stream :type t)
(prin1 (warner-option option) stream)))

(defun option-reader (in char)
(declare (ignore char))
(prog1
(make-instance 'warner-option
:option (with-output-to-string (out)
(peek-char #\] (make-echo-stream in out))))
(read-char in)))

#| ;; or if you really want the [] with the string:
(defun option-reader (in char)
(make-instance 'warner-option
:option (with-output-to-string (out)
(unread-char char in)
(with-open-stream (in (make-echo-stream in out))
(peek-char #\] in)
(read-char in)))))
|#

(set-macro-character #\[ 'option-reader)

Now, reading this:

(function-name[some text]"more text")

causes this to be returned:

(function-name #<warner-option "some text"> "more text")

You can now distinguish the option string from other strings.

Dave Pearson

unread,
Oct 7, 2002, 12:07:50 PM10/7/02
to
* Adam Warner <use...@consulting.net.nz>:

> [1]> (set-macro-character #\[
> #'(lambda (in-stream char)
> (declare (ignore char))
> (read-from-string "'(test)"))))
> T
> [2]> [
>
> *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
> #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
> macro character definition for #\[ may not return 2 values, only one value.
> 1. Break [3]>

Isn't this just an issue with the CL implementation you're using? Testing
here it seems to be an issue for CLISP but ACL, LW, Corman and CMUCL seem to
handle it with no problems.

--
Dave Pearson: | lbdb.el - LBDB interface.
http://www.davep.org/ | sawfish.el - Sawfish mode.
Emacs: | uptimes.el - Record emacs uptimes.
http://www.davep.org/emacs/ | quickurl.el - Recall lists of URLs.

Erik Naggum

unread,
Oct 7, 2002, 12:10:42 PM10/7/02
to
* Adam Warner

| *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT STRING-INPUT-STREAM>
| #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
| macro character definition for #\[ may not return 2 values, only one value.

My goodness! What horribly hostile implementation is this taken from?

| Attempting to create a splicing read macro was the whole point of the thread.

It seems that you have lost track of your problem and now focus only on a
solution that you want to make work. If one solution does not work, look
for another solution, do not try to force-fit it.

Kaz Kylheku

unread,
Oct 7, 2002, 3:24:25 PM10/7/02
to
"Adam Warner" <use...@consulting.net.nz> wrote in message news:<anohuv$fl7fs$1...@ID-105510.news.dfncis.de>...

> Hi all,
>
> I'm just a little stuck on how to turn this syntax:
>
> (function-name[some text]"more text")
>
> Into this syntax:
>
> (function-name :options "[some text]" "more text")
>
> This allows me to distinguish whether an initial optional string has been
> input. Otherwise there is no way to distinguish between these situations:
>
> (function-name "options" "text1" "text2" ...)
> (function-name "text1" "text2" ...)

In these situations, you have written neither :options nor the square
brackets. They are ambiguous because you have omitted the necessary
syntax to indicate the presence of options.

I think that :options is a perfectly good indicator, and that the [ ]
idea is just unnecessary syntactic sugar, which is hard to do, given
that a reader macro can produce exactly one object (or none by using
(values)). That syntactic sugar won't help you where you forget to use
it. If the programmer is capable of forgetting to write :options, he
is also capable of forgetting to the equivalent [ ] syntax.

Nevertheless, one hack would be to use two read macros, and pass
context between them. Ugh.

Here is the idea. Have [ trigger a read macro which reads the
following string literal, squirrels it away somewhere, and returns the
symbol :options to the reader. Then ] triggers another read macro
which retrieves the stashed string. Hence, two read macro calls, two
objects.

Adam Warner

unread,
Oct 7, 2002, 7:05:55 PM10/7/02
to
Hi Erik Naggum,

> * Adam Warner
> | *** - READ from #<INPUT CONCATENATED-STREAM #<INPUT
> | STRING-INPUT-STREAM> #<IO SYNONYM-STREAM *TERMINAL-IO*>>:
> | macro character definition for #\[ may not return 2 values, only one
> | value.
>
> My goodness! What horribly hostile implementation is this taken from?

It's CLISP 2.30. I take it you consider this implementation is conforming
in this respect?

I can see the long term benefit in refusing to allow a macro character to
return more than one value when it is not supported: This strict
implementation would make it easier to extend the functionality of the
ANSI Common Lisp reader to support splicing macros without breaking
existing code.

> | Attempting to create a splicing read macro was the whole point of the
> | thread.
>
> It seems that you have lost track of your problem and now focus only
> on a solution that you want to make work. If one solution does not
> work, look for another solution, do not try to force-fit it.

Note that I wrote at the start of the thread:

I have also tried values and read-from-string to try and return two

separate objects but I get the error message "macro character


definition for #\[ may not return 2 values, only one value."

I have not lost track of the problem. I only had to reply to fix your
misapprehension that I could ignore multiple return values from the reader
macro.

Regards,
Adam

Adam Warner

unread,
Oct 7, 2002, 8:15:09 PM10/7/02
to
Hi Erik Naggum,

> * Adam Warner
> | I'm just a little stuck on how to turn this syntax:
> |
> | (function-name[some text]"more text")
> |
> | Into this syntax:
> |
> | (function-name :options "[some text]" "more text")
>
> That is the wrong goal.
>
> | This allows me to distinguish whether an initial optional string has
> | been input.
>
> So you need a mechanism to distinguish them, not an answer to what you
> are asking for.

Not exactly. I want the second syntax to also be concise. If it wasn't for
the limitations of the Lisp reader a keyword syntax could have been the most
concise approach (I could still try an "Ugh" hack using a special variable
as outlined by Kaz in this thread).

I don't like the syntax. But I want to support it as I'll explain below.

> | Otherwise there is no way to distinguish between these situations:
> |
> | (function-name "options" "text1" "text2" ...) (function-name "text1"
> | "text2" ...)
> |
> | (Note: I am unaware of any way to attach a particular type to the
> | initial optional string so that it can be tested for as different to a
> | regular string).
>
> A wrapper class. The solution is so close you have probably
> overlooked it.

Thank you Erik. That's a very charitable interpretation :-) In fact I'm
learning about CLOS classes for the first time so the example using
defclass instead of defstruct is greatly appreciated.

Are there advantages to choosing a wrapper class instead of a struct?
It seems that a struct may be more suitable because it has a readable
representation by default. Compare:

[1]> (defclass warner-option ()


((option :type string :reader warner-option :initarg :option)))

#<STANDARD-CLASS WARNER-OPTION>
[2]> (make-instance 'warner-option :option "testing")
#<WARNER-OPTION #x203CCEFD>

With:

[3]> (defstruct warner-option option)
WARNER-OPTION
[4]> (make-warner-option :option "testing")
#S(WARNER-OPTION :OPTION "testing")

Finally, here's the reason I am attempting these weird things with
syntax: I am trying to emulate (La)TeX syntax as fully as possible within
some Lisp programs.

Not only does (La)TeX use different case to distinguish different markup
(\large, \Large and \LARGE are all different markup. I'm using a readtable
:invert to support this) but it also uses all three sets of brackets: (),
[] and {}. () is used to denote "positions" (e.g. pairs of coordinates,
size of an object).

As I'm out of paired brackets on a regular keyboard/ASCII character set I
am thinking of using <> for positions instead of () as the < macro
character is currently only used to denote unreadable content (this could
also cause complications with numerical comparisons). Perhaps a pair of
similar (but visually distinct) brackets from Unicode would be a better
idea.

In this syntax \documentclass[a4paper]{article} would be written
(documentclass[a4paper]{article})

Begin and end structures are represented as single S-Expressions:

(figure ...)

Compare: \begin{figure}...\end{figure}

This is an advantage and a disadvantage: it's an advantage with small
constructs like itemised lists. But it's a small disadvantage for large
constructs where everything else has to be nested. Compare:

(document
...)

to

\begin{document}
...
\end{document}

If I support the majority of the current TeX syntax it is easy to
translate from the TeX syntax to its Lisp representation. But to not be
chained down to the syntax it would be nice if the Lisp syntax it is
finally translated to looks like regular function options. That's why I
considered an underlying keyword syntax. I should also give consideration
to Kenny's idea of using:

(defmacro macro-name (&optional some-text) &rest other-texts)
...etc)

Regards,
Adam

Erik Naggum

unread,
Oct 7, 2002, 9:10:58 PM10/7/02
to
* Adam Warner

| Are there advantages to choosing a wrapper class instead of a struct?
| It seems that a struct may be more suitable because it has a readable
| representation by default.

That is what they specialized method on print-object was for.

I prefer structs only when there is no possible need to change the layout
of the class. Redefining a structure generally does not work, and code
that uses structures is generally inlined. You are much better off using
classes until you know very precisely what you are doing.

One reason to use a wrapper class that adds a new type to the string in
question is that keyword arguments in Common Lisp follow a fixed number
of arguments. You have to write your own parser functions to find the
options if they are flagged with keywords. This is silly and is more of
an abuse of the feature than reasonable use of it. If you have to do
some kind of dispatch, avoiding a property list that has a tail of non-
properties is a really good thing. Your need is to recognize options
when something like this is passed around, and that is fully satisfied
with a new "type" around the string.

There are many problems when processing TeX code. I really suggest you
do something that is easier to accomplish than to force a bright idea
that does not work to work.

Erik Naggum

unread,
Oct 7, 2002, 9:16:20 PM10/7/02
to
* Adam Warner

| It's CLISP 2.30. I take it you consider this implementation is conforming
| in this respect?

That was a reasonably mild restatement of what I mean. To signal an
error is just plain wrong and /will/ break conforming code.

| I can see the long term benefit in refusing to allow a macro character to
| return more than one value when it is not supported: This strict
| implementation would make it easier to extend the functionality of the
| ANSI Common Lisp reader to support splicing macros without breaking
| existing code.

Because reader macro functions are allowed to return more than one value
today, you would need a different mechanism to do something other than to
ignore them. CLISP has, however, a disturbing tradition of thinking it
is better than the ANSI Standard, although this is being improved (i.e.,
removed) as each of the cases receive public condemnation.

| I have not lost track of the problem. I only had to reply to fix your
| misapprehension that I could ignore multiple return values from the
| reader macro.

One of the annoying things with languages that have very good
specifications is that people tend to relate to the specification and
file bug reports with implementations that deviate from them. Newcomers
to a language that come from a language where there is no standard or a
bad standard such that they have to test things out in implementations,
tend to get into trouble. There is such a thing in Common Lisp as non-
conforming implementations. That concept does not exist for Python,
Perl, PHP, etc.

Adam Warner

unread,
Oct 7, 2002, 9:50:32 PM10/7/02
to
Hi Erik Naggum,

> | It's CLISP 2.30. I take it you consider this implementation is
> | conforming in this respect?
>
> That was a reasonably mild restatement of what I mean. To signal an
> error is just plain wrong and /will/ break conforming code.

I have located this statement in the HyperSpec:
http://www.lispworks.com/reference/HyperSpec/Body/02_b.htm

The reader macro function may return zero values or one value. If one
value is returned, then that value is returned as the result of the
read operation; the algorithm is done. If zero values are returned,
then step 1 is re-entered.

Only zero or one return value is defined. Any extra return values are
undefined (not illegal because "may" has been used instead of "shall" or
"may only").

As a matter of general principle should undefined behaviour never signal
an error (only a warning)?

Still, creating code with undefined consequences doesn't seem to be the
best approach. In this respect CLISP is forcing explicit compliance with
defined ANSI operations.

Regards,
Adam

Erik Naggum

unread,
Oct 7, 2002, 10:11:59 PM10/7/02
to
* Adam Warner

| Only zero or one return value is defined. Any extra return values are
| undefined (not illegal because "may" has been used instead of "shall" or
| "may only").

Extra values are always ignored in the rest of the language. It seems
odd to say the least not to ignore additional values in this particular
case.

| As a matter of general principle should undefined behaviour never signal
| an error (only a warning)?

What use could there possibly be in reporting an error for too many
values when the entire rest of the language quietly ignore them?

| In this respect CLISP is forcing explicit compliance with defined ANSI
| operations.

No, it is not. There is no specification of an error if there are more
than one value. CLISP has invented that part on its own. CLISP does a
lot of that, actually, which is why I generally discommend it just like I
discommend GCL. CLISP also teaches totally warped performance issues by
virtue of dramatically different performance for system and user code.

Alexey Dejneka

unread,
Oct 7, 2002, 11:37:51 PM10/7/02
to
Hello,

Erik Naggum <er...@naggum.no> writes:

> * Adam Warner
> | Only zero or one return value is defined. Any extra return values are
> | undefined (not illegal because "may" has been used instead of "shall" or
> | "may only").
>
> Extra values are always ignored in the rest of the language. It seems
> odd to say the least not to ignore additional values in this particular
> case.

* (multiple-value-call (lambda (&optional (x nil x-p)) (list x x-p))
(values 1 2))
debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
invalid number of arguments: 2

It it wrong too?

--
Regards,
Alexey Dejneka

Christophe Rhodes

unread,
Oct 8, 2002, 4:04:20 AM10/8/02
to
Erik Naggum <er...@naggum.no> writes:

> * Adam Warner
> | Only zero or one return value is defined. Any extra return values are
> | undefined (not illegal because "may" has been used instead of "shall" or
> | "may only").
>
> Extra values are always ignored in the rest of the language. It seems
> odd to say the least not to ignore additional values in this particular
> case.

I don't know... if it were documented in CLISP's implementation notes
that an interpretation (say, "splicing read macro") for more than one
return value was being considered, but had not yet been implemented, I
would say that throwing an error at this point was a logical thing to
do[1], simply to point out the possibility of this behaviour changing.

I generally find that I want to know when I am invoking undefined
behaviour, if only because such behaviour may change at any time.

Christophe

[1] I might prefer a STYLE-WARNING.
--
http://www-jcsu.jesus.cam.ac.uk/~csr21/ +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%") (pprint #36rJesusCollegeCambridge)

Frode Vatvedt Fjeld

unread,
Oct 8, 2002, 5:45:17 AM10/8/02
to
"Adam Warner" <use...@consulting.net.nz> writes:

> I used (first (list ...)) to get rid of the second return value of
> read-from-string. There is probably a better way that I am unaware
> of.

The standard idiom would be (values <form>), I believe. If you need to
pick out a value other than the primary one, use nth-value.

--
Frode Vatvedt Fjeld

Erik Naggum

unread,
Oct 8, 2002, 11:20:57 AM10/8/02
to
* Alexey Dejneka <adej...@comail.ru>
| It it wrong too?

*sigh*

Vassil Nikolov

unread,
Oct 8, 2002, 11:25:30 AM10/8/02
to
On 08 Oct 2002 07:37:51 +0400, Alexey Dejneka <adej...@comail.ru> said:

AD> * (multiple-value-call (lambda (&optional (x nil x-p)) (list x x-p))
(values 1 2))
AD> debugger invoked on condition of type SB-INT:SIMPLE-PROGRAM-ERROR:
AD> invalid number of arguments: 2

AD> It it wrong too?

Your example is like (APPLY (LAMBDA ...) '(1 2)) which is different
from (FUNCALL (LAMBDA ...) (VALUES 1 2)). The latter is the case
where extra returned values are ignored.

(I know FUNCALL is redundant in the above expression taken as a
literal example.)

Vassil Nikolov

unread,
Oct 8, 2002, 11:36:03 AM10/8/02
to
On 08 Oct 2002 02:11:59 +0000, Erik Naggum <er...@naggum.no> said:

EN> Extra values are always ignored in the rest of the language.

Where the caller accepts exactly one value, certainly. But are
there any cases where the caller accepts a variable number of
values, up to N-1, and is explicitly defined to ignore the Nth
value and beyond? Or is there a general rule to that effect?

Erik Naggum

unread,
Oct 8, 2002, 6:41:39 PM10/8/02
to
* Vassil Nikolov

| Where the caller accepts exactly one value, certainly. But are
| there any cases where the caller accepts a variable number of
| values, up to N-1, and is explicitly defined to ignore the Nth
| value and beyond? Or is there a general rule to that effect?

If you accept n values in `multiple-value-bind´, any extraneous values
are ignored. Missing values are even bound to `nil´. The one exception
to this is `multiple-value-call´ where the returned values are arguments
to another function, but that is because Common Lisp does not ignore
extraneous arguments to functions without `&rest´, nor accept fewer
arguments to function without `&optional´ or `&key´.

So, where is the function that accepts one optional argument and which is
called with `multiple-value-call´ of the values of reader macro functions?

Vassil Nikolov

unread,
Oct 9, 2002, 3:46:48 AM10/9/02
to
On 08 Oct 2002 22:41:39 +0000, Erik Naggum <er...@naggum.no> said:

VN> Where the caller accepts exactly one value, certainly. But are
VN> there any cases where the caller accepts a variable number of
VN> values, up to N-1, and is explicitly defined to ignore the Nth
VN> value and beyond? Or is there a general rule to that effect?

EN> If you accept n values in `multiple-value-bind´, any extraneous values
EN> are ignored. Missing values are even bound to `nil´. The one exception
EN> to this is `multiple-value-call´ where the returned values are arguments
EN> to another function, but that is because Common Lisp does not ignore
EN> extraneous arguments to functions without `&rest´, nor accept fewer
EN> arguments to function without `&optional´ or `&key´.

EN> So, where is the function that accepts one optional argument and which is
EN> called with `multiple-value-call´ of the values of reader macro functions?

Well, I never suggested there was one. (But I will suggest a
similar one below, so this question is quite anticipative.)

I admit I overlooked MULTIPLE-VALUE-BIND's ignoring excess values,
and that behavior does support the notion that if a caller is
defined to accept up to a certain number of values, then implicitly
this means that extra values are ignored.

But to make the above argument complete, it must be noted that the
reader cannot use MULTIPLE-VALUE-BIND to call the macro reader
function since if it did, it wouldn't know when zero values were
returned. (MULTIPLE-VALUE-BIND is somewhat inappropriate when the
number of values returned can be less than the maximum number of
values consumed, i.e. than the number of vars.) Therefore, there
are two ways to implement the reader:

(1) By using MULTIPLE-VALUE-LIST to receive the values returned by
the reader macro function. This is the more straightforward
implementation, and it leads naturally to a logic where the
list thus obtained is tested first for being empty, and then,
if it is not, its first element is extracted, while the rest of
the elements, if any, are silently ignored.

(2) By using MULTIPLE-VALUE-CALL, with a function whose lambda list
is something like

(&optional (read-value nil read-value-p) &rest ignore)

where the implementor must be `smart enough' since the &REST
parameter must be explicitly added. If it isn't, then it will
be an error for the reader macro function to return more than
one value.

I can see how MULTIPLE-VALUE-BIND's behavior together with the
`naturalness' of (1) make the point for accepting two or more
values from the reader macro function, but I still find that part
of the standard a little underspecified^1 (MULTIPLE-VALUE-BIND does
not apply directly, and there is no explicit statement about what
happens if neither zero nor one values are returned by the reader
macro function---it `may return zero values or one value' but `may'
is not formally defined).

Erik Naggum

unread,
Oct 10, 2002, 5:02:48 PM10/10/02
to
* Vassil Nikolov

| But to make the above argument complete, it must be noted that the reader
| cannot use MULTIPLE-VALUE-BIND to call the macro reader function since if
| it did, it wouldn't know when zero values were returned.

Correct, and a good point.

| (1) By using MULTIPLE-VALUE-LIST to receive the values returned by the
| reader macro function. This is the more straightforward
| implementation, and it leads naturally to a logic where the list thus
| obtained is tested first for being empty, and then, if it is not, its
| first element is extracted, while the rest of the elements, if any,
| are silently ignored.

In this model, which I think is the most rational choice, it takes extra
effort to check for the redundant values.

| (2) By using MULTIPLE-VALUE-CALL, with a function whose lambda list
| is something like
|
| (&optional (read-value nil read-value-p) &rest ignore)
|
| where the implementor must be `smart enough' since the &REST
| parameter must be explicitly added. If it isn't, then it will be an
| error for the reader macro function to return more than one value.

But this model, while possible, would mean that the function so called
would be a closure that would act on the hitherto collected elements of a
list or other structure. Remember,we are using this to collect datums
from a stream to return to our caller. It seems strange to do this with
a downward-passing mechanism that would collect upon return.

However, the more I think about this, the more I think that maybe the
support for multiple-values in Common Lisp is slightly lacking. More
often than not, multiple values may be returned in registers, but there
is no way to access both the values and the number of returned values
even though most (if not all) implementations return that number with the
returned values. When multiple values are returned, a function should be
able to dispatch on the number of return values. The only way to do this
is with `multiple-value-call´ and hope that the multiple-value-return
block and the argument block to a function are not too costly to convert
between.

It would be interesting to compare the various implementations on this
point.

0 new messages