[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