[gambit-list] strange results using values
Christian Jaeger
christian at pflanze.mine.nu
Mon Sep 22 21:06:16 EDT 2008
(Before replying let me remind ourselves that there are two things in
this thread:
(1) whether the semantics of Gambit or that of dropping superfluous
values is the better one. Or at least making each of us understand each
other's points. (And I think, I do see the point that you'd like to have
that comfort of just ignoring some less-important values that you might
not always want, this is easy to see. And you'd like not having to
specify anything syntactically on the receiver side to get this. I do
question the merit of this versus the problems of it, though.)
(2) whether there is a good way unifying both approaches in one and the
same system, with hopefully workable integration of code of both
philosophies.
Let me state that I'm a bit unclear which of those you are targetting
below at some places.)
Arthur Smyles wrote:
> My understanding of this issue is clearer. But see comments below
> ...
> This only works because Gambit doesn't return multiple values. As Marc
> mentioned earlier, (values 1 2) is currently implemented as a vector
> with a special type.
(The implementation doesn't really matter (they could also be stored in
global variables if the implementation wouldn't have to deal with
call/cc or threads, or the vector could be optimized away if the
consumer is the direct continuation of the producer); the fact how they
are being implemented will just make clear how they behave. The point is
that the multiple values are being tunneled through continuations which
are not "prepared" (so to speak) of taking multiple values, until they
reach a continuation which is.)
> So you can achieve the same thing using the user code:
>
> (define (dosomequery-with-x x)
> (db-transaction mydb (lambda ()
>
> (let ((a (db-query mydb "foo" x))
> (b (db-query mydb "bar" x)))
> (list a b)))))
>
> (apply (lambda (a b) ...) (dosomequery-with-x 1234))
>
Yes, I already said "As I said, and as has [been] discussed many times,
yes, multiple-values is kind
of redundant" (not sure why you're bringing this up again, but I guess
you're looking after that additional benefit they would provide you).
> If the library wanted to be multi-value aware,
My point was that as library author I *don't want* to remember having to
make everything multi-value aware.
(It's like not casting a data type in stone: I don't want to cast in
stone how many values are being passed through a function of mine by the
user of that function.)
> then it could be
> re-written as:
>
> (define (db-transaction db thunk)
> (db-begin! db)
> (with-exception-catcher
> (lambda (e)
> (db-rollback! db)
> (raise e))
> (call-with-values
> thunk
> (lambda vals (db-commit! db) (apply values vals)))))
>
> This makes sense since only call-with-values will create a multi-value
> continuation. call/cc by default only creates single-value continuations.
>
(call/cc makes continuations first class, it doesn't create them [well,
it may create a continuation *object* representing the continuation]. A
continuation captured by call/cc will expect exactly as many values as
the continuation of the call/cc call takes (because it's the same).)
(What do you mean when you say "This makes sense"?)
Are you suggesting that I should really write my code as you have shown
above? If so, I would have thought that it shows quite clearly why the
approach of dropping values is flawed. You don't think so?
Tunneling multiple values without having to change the code makes
"normal" Scheme code automatically compatible with multiple values,
that's the good thing about the tuples/Gambit approach.
> ...
> I think you've given me an idea as a workaround to simulate what I want
>
> (define (mv-fun . k)
> (if (pair? k)
> ((car k) #f #f)
> #f))
>
I don't understand. What would you pass to mv-fun?
> In which case if I want the multiple-values I have to explicitly pass
> the continuation. I'd rather have the scheme implementation hide this
> stuff with values/call-with-values then have this kind of plumbing in
> apis that I'd develop.
>
I'd rather specify places where I expect multiple values explicitely
than having to change all code which would *possibly* need to deal with
a user expecting to be able to pass multiple values through. Since the
former are few, whereas the latter could be *every* function.
Am I missing something?
> So my take away from the discussions so far are:
>
I have big difficulties understanding the following paragraph.
> If your scheme implementation does not support multi-value continuations
>
What is your definition of a scheme implementation which does support
multi-value continuations?
In the R5RS sense, Gambit is one, as are the implementations which drop
values. All of them do support multi-value continuations --
continuations which are created by call-with-values.
The difference is whether *other* continuations ("normal" ones) are
behaving like (lambda (value . ignored) ..) including always dissecting
the values immediately in the continuation the values are being passed
to, or (lambda (value) ..) *without* dissection.
So (my guess) you are counting Gambit into the camp which "does not
support multi-value continuations"?
> then don't bother with values/call-with-values.
Why not?
> They are basically
> standardized hooks
Why "hooks"?
> for implementations that do support multi-value
> continuations.
>
What do you want to say? "Since |values| does not offer new features
over |list| in an implementation like Gambit, don't bother using it
there", or something else?
Christian.
More information about the Gambit-list
mailing list