kawa-commonlisp-dev
[Top][All Lists]
Advanced

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

[Kawa-commonlisp-dev] Multiple value binding


From: Charles Turner
Subject: [Kawa-commonlisp-dev] Multiple value binding
Date: Fri, 3 Aug 2012 15:16:28 +0100

We've discussed this on the main list, but I think the thread diverged
onto something else before it was resolved.

The problem is this, I currently have implemented the
MULTIPLE-VALUE-BIND macro like so:

(define-syntax multiple-value-bind
  (syntax-rules ()
    ((_ parameters producer body ...)
     (call-with-values (lambda () producer)
       (lambda parameters body ...)))))

Here are some CL-idiom/standard violations:

1> (multiple-value-bind (x) (values 1 2 3) (list x))
;gnu.mapping.WrongArguments: call to 'gnu.expr.ModuleMethod' has too
many arguments (2; must be 1)
2> (let ((x (values 1 2 3))) (list x))
(1 2 3)

I'm getting around the first simply by providing superfluous
arguments. The second one is quite thorny though, because in my
DEFMACRO code, I have a function like this:

(defun f ()
  (if whatever
     ; expression returing multiple values, the first of which is a list
     ; expression returing a list))

and F is used in lots of different places, assuming different
contexts, like (multiple-value-bind (a b c) (f)) and (when (f) ...).
The only solution to this would be to modify F so that it always
returns multiple values, and then modify all call-sites to accomodate
for this. It's rough, so I thought I'd rekindle this discussion again.

Jamison provided some insightful comments which were not expounded on
any further due to the disorganisation of my previous threads. I quote
below:

--------------------------------8<----------------------------------

The problem basically is that in Kawa, values objects (instances of
gnu.mapping.Values) are regular first-class objects and not language
trickery and so they have no special handling. There's nothing in place
that examines the current continuation to see whether the expected number
of values matches the number being passed.

Note that this behavior is allowed in Scheme. R6RS says:

    The continuations of all non-final expressions within a sequence of
    expressions, such as in lambda, begin, let, let*, letrec, letrec*,
    let-values, let*-values, case, and cond forms, usually take an arbitrary
    number of values.

    Except for these and the continuations created by call-with-values,
    let-values, and let*-values, continuations implicitly accepting a single
    value, such as the continuations of <operator> and <operand>s of
    procedure calls or the <test> expressions in conditionals, take exactly
    one value. The effect of passing an inappropriate number of values to
    such a continuation is undefined.


So the spec says:
((lambda (x) x) (values 1))   => 1
((lambda (x) x) (values 1 2)) => undefined
((lambda (x) x) (values))     => undefined

and kawa --scheme performs:
((lambda (x) x) (values 1))   => 1
((lambda (x) x) (values 1 2)) => #<values 1 2>
((lambda (x) x) (values))     => #!void

Common Lisp, on the other hand, mandates:
((lambda (x) x) (values 1))   => 1
((lambda (x) x) (values 1 2)) => 1
((lambda (x) x) (values))     => NIL

Use the first if there are multiple, otherwise use NIL.

[Yet another meaning for NIL! Who's keeping track? So far we've
got it (potentially at least) meaning '(), #f, #!null, and #!void.]

So, we need to have some kind of mechanism in place to coerce
gnu.mapping.Values objects into single values as if by

if (object instanceof Values)
{
  Object[] vals = ((Values)object).getValues();
  if (vals.length > 0) return vals[0];
  else return NIL;
}
else
{
  return object;
}

Maybe that should be done by something akin to the Promise.force() calls
that are sprinkled throughout the code and automatically get inserted
by the compiler?

I'm ambivalent about how it should work in Scheme. The existing behavior
is consistent with the spec, and it's the only solution that doesn't discard
information. On the other hand, one reason that multiple values is such a
handy and widely-used thing in Common Lisp is *because* the extra returns
can get automatically dropped. It's kind of annoying that in Scheme you have
to use something like an explicit let-values to bind all the returns and then
just use the first.

I do think that Scheme should retain the 0-value case, though:
((lambda (x) x) (values))     => #!void, not #f or #!null or '()

So Values#force() [or whatever] needs to check the current Language
to see whether it should return NIL or #!void.

Per, what are your thoughts

-------------------------------->8----------------------------------

Should I go for the rough solution and continue testing
DESTRUCTURING-BIND or try to pursue the approach outlined by Jamison?

Kind regards,
Charles.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]