[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Multiple values for R4RS
Permit me a few remarks on how the Scheme reports have said what is
best left unsaid, and then I will explain why it is important to me
that (VALUES E) be the same as E.
Undefined is fine with me. I previously suggested the possibility of
phrasing it as an implementation restriction. That would also be
What you want to say is that "the effect is unspecified" or (speaking
of a procedure) "its behavior is implementation dependent". For
examples of both, see the description of WITH-INPUT-FROM-FILE.
"Undefined" is bad because it has a definite meaning in Scheme: if the
value of a variable is undefined, then it is an error to reference that
variable. The use of undefined as an actual value is explicit in section
7.2 and is almost explicit in section 7.3. "Implementation restrictions"
are discouraged, which may be the effect you want in this case but would
not be likely to make your political opponent(s) happy.
The net result for Common Lisp was that the old CLtL "is an error"
terminology will be replaced in ANSI CL by a whole bunch of new terms,
which cover the same turf in more refined fashion....I could pass along
the current draft meanings of those terms if anyone on Scheme was
serious about establishing some more refined error terminology.
I looked at the new CL terminology and decided not to use it, though
I added the notion of an implementation restriction.
I don't think a more refined error terminology would help us much.
In the last couple of days I've read about ten messages debating
Returning zero values or more than one value to something other
than a receiving procedure is an error.
versus something like
The effect of returning zero values or more than one value to
something other than a receiving procedure is unspecified.
when the real sticking point, as I see it, is the one-value case:
As an implementor, I would like to signal an error whenever someone
attempts to return (values ...) to a context where multiple values
aren't expected, or something other than (values ...) to a context
expecting multiple values. Requiring "(values e)" to be the same as
"e" makes it impossible to do this. As you pointed out in your note,
this won't affect anyone who doesn't like this behavior, since they
can always create their own versions of "values" and "with-values"
that circumvent the error checks.
The reason I don't like a semantics in which (VALUES E) is not required
to be the same as E doesn't have anything to do with whether I can
implement the semantics I like (I can, regardless). It has a little bit
to do with whether I can write certain portable programs (see example
below), but not much. It mainly has to do with the complexity of Scheme
considered as a programming language independent of its implementations.
The only way that I can see to understand or explain a semantics in
which (VALUES E) is not required to be the same as E is to postulate
an entirely new kind of object whose sole purpose is to communicate
between VALUES and receivers of multiple values. I then have to say
that the effect is undefined (or an error) if this new kind of object
ever gets passed to an ordinary continuation, procedure, or special
form (e.g. IF). That's a considerable amount of intellectual overhead
if the only reason for it is to allow some particular implementation
"to signal an error whenever someone attempts to return (VALUES ...)
to a context where multiple values aren't expected, or something other
than (VALUES ...) to a context expecting multiple values".
I think anyone who wants to impose this extra semantic complexity on
Scheme as the price for multiple values ought to explain why it is so
desirable for an implementation to signal an error in the circumstances
Here's an example of a potentially useful procedure that would be
less useful if (VALUES E) is not required to be the same as E:
; Given two procedures F and G, COMPOSE returns a procedure that
; acts as the composition of F and G. The arguments to F consist
; of all the values returned by G.
(define (compose f g)
(receive-values (lambda () (apply g args))
(lambda results (apply f results)))))
(define h1 (compose (lambda (x) (+ x 1)) *))
(h1 3 4) ==> 13
(define h2 (compose + (lambda (x y) (values (* 2 x) (+ y 1)))))
(h2 3 4) ==> 11
And this is the feature I'm most critical of. Unless an implementation
does support the truncation feature, I don't see any reason why we should
require that "(values e)" be equivalent to "e". I would like to feel
free to signal an error if "(values e)" is returned to a context that
is not prepared to accept multiple values.
I have given two reasons in this message, both of which are independent
of the truncation feature. I'm curious to know what you think of them,
and even more curious to know why signalling that error is so important
Incidentally, the proposed ACCEPTS? procedure also complicates the
language (because the denotations of procedures would have to carry
their arity), but the complication is fairly slight and the claimed
benefit is clearer. It is my impression that the benefit is about
as meager as the complication, but at least I understand the argument.
Also incidentally, the people who have been explaining how easy it
is to implement ACCEPTS? seem to have been assuming that the Scheme
implementor has control over the calling sequences and/or compilers.
It's not so easy if your goal is to build a Scheme system that uses
standard calling sequences and can call separately compiled C code
(say) without having to interpose a trampoline or other crock. That's
hard enough without having to define ACCEPTS? for unknown C procedures.