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

Multiple Values: A Survey

		       Multiple Values:  A Survey

The current proposal (from Will's lunch minutes) for multiple return
values consists of the two functions:

  (receive-values <fcn> <mv-thunk>)
which applies <fcn> to the multiple values returned by <mv-thunk>.  And:

  (return <v1> ... <vN>) or
  (values <v1> ... <vN>)

which returns the values <v1> ... <vN>.

Also, in the semantics there is an auxiliary function single, which
currently raises an error if multiple values are returned.  Question (3)
deals with issue of making the auxiliary function available in the
language and questions (7) and (10) indirectly deal with the semantics
for single.

1) Syntactic questions:

   1a) What argument order do we want for receive-values?

   1b) Do we want to use a different name for receive-values? Eg.
       Multiple-value-call, multiple-value-apply, or something else?

   1c) What name do we want for the multiple value return construct?
       Return, values, something else?

2) Do we want receive-values and return to be essential or

3) Do we want to incorporate the auxiliary semantic function single
into the language (see also (6b)) as:

	(single <mv-thunk>)

such that

	(single (lambda () (return <v1> ... <vN>))) => <v1>.

Should it be essential or non-essential?

4) Should receive-values allow multiple multiple-value-thunks in a manner
similar to Common Lisp's multiple-value-call?  That is all the values
from the various multiple-value-thunks would be "concatenated" before
being passed to the function. 

5) Interaction with call-with-current-continuation.  How are multiple
values returned from a continuation?  Presumably, 

	  (lambda (cont)
	        (cont (return <v1> ... <vN>))))

does not work since the (return <v1> ...  <vn>) is in argument position.
Furthermore, I presume that 

	   (lambda (k)
	           (lambda () (return <v1> ... <vN>)))))

won't work, since the escape procedure generated by call/cc is a
"function" of one argument, which would make the above application of
receive-values analogous to:

       (receive-values (lambda (x) ...)
		       (lambda () (return <v1> ... <vN>)))

which (presumably) is an error. 

    5a)  Modify continuations to take a variable number of arguments that
are returned as the multiple values of the continuation.  Eg. 

	(k <v1> ... <vN>)

    5b)  Add a new procedure called 
call-with-multiple-values-current-continuation (or call/mv/cc for short)
that takes a function of one argument, a multiple value escape
procedure.  The escape procedure takes a thunk as an argument and
transmits the values returned by the thunk.  Eg. 

	   (lambda (k)
	       (k (lambda () (return <v1> ... <vN>)))))

    5c)  Somehow modify the existing version of call/cc so that when the
escape procedure k is invoked, (k v) returns v and

	(receive-values k (lambda () (return <v1> .. <vN>)
returns <v1> ... <vn>.  

    5d) Somehow modify multiple values so that they can be cohesively
returned in argument position.  I.e. so (cont (return <v1> ... <vN>)
would work.  (See Opinion message.)

    5e) Something else?

6) What forms pass multiple values through?

More likely than not the following (relatively) tail recursive forms
pass back multiple values. 

    6a) Do LAMBDA, LET and LETREC pass back multiple values from their

    6b) Do IF, COND and CASE pass back multiple values from the arms of
        the conditional?

    6c) Does explicit and implicit BEGIN blocks pass back multiple values 
        from the last form in the block?

But what about other forms?			

    6d) Does DO pass back multiple values from the last form in the exit

    6e) Do AND and OR pass back multiple values from the last form? Or
        in OR's case from any form?

    6f) Can FORCE return multiple values?  (If so how is DELAY
        implemented (i.e. how is make-promise written))

    6g) What other forms pass back multiple values?

    6h) Are there any forms that never pass back multiple values?

7) What happens when multiple values are returned to a context which
doesn't expect them as in predicate position within a conditional or
argument position within an application.  For example:

	(if (return v1 ... VN)


        (f (return v1 ... VN) ...)

  7a) Coerce the multiple values to a single value as in Common Lisp.  
  7b) Instantiate a (first class) multiple values object (see Opinion

  7c) It would be an error.

  7d) An error would be signaled.

  7e) Other?

8) Do we want to augment existing binding forms (let, let* letrec) to
destructure multiple values or introduce a multiple value version for
each binding form, or not include such a capability?  In each of the
following examples, b1 would be bound to <v1> ... and bN to VN.  Which
is preferred? 

    8a)	(let (((b1 ... bN)              ;; i.e. ((ids*) <exp>)
	       (return <v1> ... <vN>))

    or (perhaps)

    8b)	(multiple-value-let    or (8c) (multiple-value-let
	   (b1 ... bN)                    (((b1 ... bN) 
	   (return <v1> ... <vN>)           (return <v1> ... <vN>))
	   <body>)			    <other-bindings>)

    8d)  other

Should (a)-(d) (if any) be essential or non-essential?

9) Similarly, do we want to augment set!  and define to accept multiple
values, define new versions of these constructs or not include these
constructs?  (In the case of define, augmentation would be incompatible
with the non essential forms of define.)  Do we want to make this
essential or non-essential syntax?  In the case of set!, which of the
following is preferred?

   9a)	(set! (id1 ... idN) (return <v1> ... <vN>))
        And (b) or (c) for define.

   9b)	(multiple-value-set! (id1 ... idN) (return <v1> ... <vN>))
        (multiple-value-define (id1 ... idN) (return <v1> ... <vN>))


   9c)	(multiple-value-set! id1 ... idN (return <v1> ... <vN>))
        (multiple-value-define id1 ... idN (return <v1> ... <vN>))


   9d)   other

10) For those constructs that expect multiple values (presumably,
receive-values, multiple-value-let, multiple-value-let*,
multiple-value-letrec, and multiple-value-set!)  what happens when too
few or too many values are returned.  For example in:

	   (((Id1 ... IdM) (return <v1> ... <vN>)))

M arguments are expected and N arguments are returned.

   10a)  N > M  More values returned than expected.

	1) Ignore extra values.
	2) It is an error.

	3) An error is signaled.

	4) other.

   10b) M > N  More values expected than returned.

	1) Return as many as needed additional default values. 
	2) It is an error.

	3) An error is signaled.

	4) other.

11) What (if any) other constructs do we want for returning multiple
values?  What should their names be?  Do we want a thunk or an
expression for the multiple values form (see (6c)).  Should these
constructs be essential or non-essential?

   11a) the equivalent of (receive-values (lambda x x) <mv-form>)

       1) (multiple-value-list <mv-thunk>)   or 
       2) (values->list <mv-thunk>) or
       3) none
       4) other

   11b)  The equivalent of (apply values <list>)

       1) (values-list <list>)
       2) (list->values <list>)
       3) none
       4) other
   11c)  The equivalent of
       (receive-values (lambda x (list->vector x)) <mv-form>)

       1) (multiple-value-vector <mv-thunk>)   or 
       2) (values->vector <mv-thunk>) or
       3) none
       4) other

   11d)  The equivalent of (apply values (vector->list <vector>))

       1) (values-vector <vector>)
       2) (vector->values <vector>)
       3) none
       4) other

   11e)  Any others?