Newsgroups: comp.lang.scheme
Path: cantaloupe.srv.cs.cmu.edu!das-news2.harvard.edu!news2.near.net!howland.reston.ans.net!gatech!udel!princeton!news.princeton.edu!blume
From: blume@atomic.cs.princeton.edu (Matthias Blume)
Subject: Re: giving up (Was: Re: Explanation about call-with-values)
In-Reply-To: "R. Kent Dybvig"'s message of Thu, 26 Jan 1995 17:44:27 -0500
Message-ID: <BLUME.95Jan27114524@atomic.cs.princeton.edu>
Originator: news@hedgehog.Princeton.EDU
Sender: news@Princeton.EDU (USENET News System)
Nntp-Posting-Host: atomic.cs.princeton.edu
Organization: Princeton University
References: <BLUME.95Jan22133847@dynamic.cs.princeton.edu> <3g004e$7ps@nkosi.well.com>
	<BLUME.95Jan23140314@dynamic.cs.princeton.edu>
	<3g67ne$e4e@narnia.ccs.neu.edu>
	<BLUME.95Jan25165400@atomic.cs.princeton.edu>
	<1995Jan26.174431.9717@news.cs.indiana.edu>
Date: Fri, 27 Jan 1995 16:45:24 GMT
Lines: 126

In article <1995Jan26.174431.9717@news.cs.indiana.edu> "R. Kent Dybvig" <dyb@cs.indiana.edu> writes:

   [ ... ]  We were using macros for
   call-with-values and values.  The macros chose between a list or vector
   representation depending upon the number of values to be returned or
   accepted.  (The macro for call-with-values required that the consumer
   be a lambda expression.)  The only rewriting we did was to eliminate
   the macros and use the new built-in versions of call-with-values and
   values.

   Since most of the computation in the concerned passes was performed in
   registers, the memory operations involved in creating the lists and
   vectors and taking them apart added up to a significant portion of the
   total run time.  And with our implementation call-with-values and
   values now do take essentially zero time (for integrable calls where
   the consumer is a lambda expression).

Ok, so I eat my words.  20%.  Still, have you compared these numbers
to explicit CPS.  This should give you the same benefits...

   >   Not so.  Lists and vectors are first class.

   >Exactly.  It is against the spirit of Scheme -- as I understand it,
   >and as far as the language still has one -- to have a procedure
   >(`values') to construct second-class objects.  I still don't
   >understand why first-class-ness prevents us from taking advantage of
   >Wright's soft typing or similar kinds of analyses.

   It isn't against the spirit or reality of Scheme.  The values are still
   first class, we just aren't committing to any sort of container for
   them.

No, they are not `first class'.  I cannot call the `values' procedure
in most contexts where I can call any other function.  If it was
first-class, then I could say:

	(define x (values 1 2 3))

and then

	(call-with-values (lambda () x) list) -> (1 2 3)

   Single return values don't come in a first-class container
   either, but you don't complain that they aren't first class.

Sorry, but that is a silly argument.  If a single values needs a
container, which is first-class and therefore a single value in
itself, we would need a container for the container, and a container
for the container of the container, ...

This whole discussion shows that multiple values are not just a
straight-forward extension to single values.  They are something
conceptually different.  They are containers!  As a matter of fact, I
would prefer (eq? (values 2) 2) to be #f, just like (eq? (list 2) 2)
is #f. 

   Arguments
   don't come in first-class containers, although the syntax of lambda
   allows us to put them in one (a list).  And as you point out you can do
   the same thing with call-with-values (and with macros, you can make
   doing so very concise).

Actually, I would like to have all functions take just exactly one
argument.  If you want to pass more, then pass a container!  (Witness SML!)
This would make things symmetrical, and it would also settle your
complaint about list/apply not properly taking care of call/cc's behavior.

   >I do not understand why we suddenly give up on the goal of conceptual
   >simplicity, and the goal of power through orthogonality.  In my eyes,
   >`values' is a performance hack and as such it doesn't belong into a
   >language like Scheme.

   Perhaps.  I fought against multiple return values along these lines,
   but I was finally convinced to agree to them based on arguments of
   portability and readability of code.  Multiple return values do make
   some code much more readable, and there's no doubt that they can
   eliminate a lot of consing if implemented properly.

I maintain my assertion: with sufficient work in the area of compilers
we can avoid the same (or nearly the same) amount of consing.  I do
not see the justification for the `portability' claim.  And, last but
not least, `readability' -- that's a matter of taste.  To me,
call-with-values is utterly unreadable, but perhaps that's just me.
And since you can achieve the same `beauty' or `ugliness' without
having a magic built-in `values' procedure this can hardly count as
an argument.

   > ... `values' is a blatant symptom of feature cancer.  It is
   >easy to define in other terms:

   >        (define values list)
   >        (define (call-with-values thunk receiver)
   >          (apply receiver (thunk)))

   >The properties of this pair of functions contain those of the proposed
   >values/call-with-values. ...

   It's not this simple, since this doesn't handle reified continuations
   of arities other than one.

I see what you mean.  But, IMO, this is a good thing -- and it fits
right in with my argument that *all* procedures should take exactly
one argument.  If we make the container first-class (and therefore
distinguish between the container and the things contained therein),
then returning many values means returning *one* thing: the container!
Therefore, the continuation *does* take only one argument (the
container).

Sometimes I might want to say:

	(call/cc
	  (lambda (k)
	    (let ((r (f ...)))
	      <do something else>
              (if (panic? ...) (k r))
              <do even more>
              r)))

I.e., I want to capture the return value(s) of the call to `f' and
pass them on to my continuation, and this should look the same no
matter whether my continuation takes one or many (or no) values.
(This is obviously a silly example, and it could easily be written
without call/cc, but you get the idea...)

--
-Matthias
