[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: multiple return values
From: |
Neil Jerram |
Subject: |
Re: multiple return values |
Date: |
03 Aug 2001 13:15:16 +0100 |
User-agent: |
Gnus/5.0808 (Gnus v5.8.8) Emacs/20.7 |
>>>>> "Matthias" == Matthias Koeppe <address@hidden> writes:
Matthias> Marius Vollmer <address@hidden> writes:
>>
>> The question is now, do we want to allow ignoring superflous
>> values, or should that be an error. I'm in favour of allowing
>> them to be ignored.
Matthias> I think it is a bad idea because it encourages writing
Matthias> non-portable code: R5RS (Control Features) says that
Matthias> "Except for continuations created by the
Matthias> `call-with-values' procedure, all continuations take
Matthias> exactly one value." Clinger also calls this situation
Matthias> (passing multiple values to single-value continuations)
Matthias> an error in his posting. Hence, your proposed change
Matthias> does not make the m-v implementation more "correct".
Matthias> [...]
I agree with Matthias. I also noticed this clause in R5RS recently
(in the context of a multiple values version of `map' - appended below
for interest), and it seems to be pretty conclusive. I also agree
that there is no strong reason to treat truncation to one value more
specially than, say, to two values.
Matthias> If I have read Clinger's posting correctly, he actually
Matthias> suggested to check for a multiple-value context by
Matthias> looking at the `return address', i.e. at the
Matthias> continuation of the `values' call. I don't know if
Matthias> that's easily possible in Guile, though. If it is, that
Matthias> would be a real alternative and improvement to the
Matthias> current implementation because it would allow for proper
Matthias> error checking without imposing runtime penalties for
Matthias> single-value situations.
Doesn't this boil down just to a `multiple_value_continuation_p' local
variable on the stack in the evaluator, which is initialized to 0 but
set to 1 by the code that handles `call-with-values'. Then, as long
as we've got tail recursion right, multiple_value_continuation_p will
remain set for any context that is in tail position with respect to
the `call-with-values' expression.
Neil
(define-module (ossau map-mv)
#:export (map-multiple-values map/mv))
(define (map-multiple-values proc arg1 . args)
"Like @code{map} but handles multiple values from @code{proc}.
If any of the calls to @code{proc} return multiple values,
each of the multiple values is added to @code{map-multiple-value}'s
list of results. It follows that the complete results list
may not have the same length as the lists of input arguments.
@example
(map-multiple-values (lambda (x)
(values x (* x 2)))
'(10 100 1000))
@result{}
(10 20 100 200 1000 2000)
@end example"
(let ((arg1l (length arg1)))
(for-each (lambda (argn)
(or (= (length argn) arg1l)
(error "Lists have differing lengths!")))
args))
(let ((result '()))
(let loop ((arg1 arg1) (args args))
(if (null? arg1)
(reverse result)
(begin
(call-with-values
(lambda ()
(apply proc (car arg1) (map car args)))
(lambda values
(for-each (lambda (value)
(set! result (cons value result)))
values)))
(loop (cdr arg1) (map cdr args)))))))
(define map/mv map-multiple-values)
;;; map-mv.scm ends here