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

Re: [srfi-11] LET-VALUES wrapup (was: Re: Another vote for more parens)

This page is part of the web mail archives of SRFI 11 from before July 7th, 2015. The new archives for SRFI 11 contain all messages, not just those from before July 7th, 2015.



Okay, here's a summary of the proposal I see coming down the bend
(note that I don't like it, I'm just summarizing it *smile*)...

Syntax:

  EXP ::= (let-values (DECL ...) BODY)
        | (let*-values (DECL ...) BODY) ;; or let-values*?
  
  DECL ::= (IDENTIFIER EXP) 
         | (FORMALS* EXP)

  FORMALS* ::= everything that the <formals> nonterminal from R5RS
               7.1.3 can be, _except_ for just an <identifier>.

Semantics (for just one decl, because I'm lazy)

  (let-values ((IDENTIFIER EXP)) BODY) 
  ==> (let ((IDENTIFIER EXP)) BODY)
         or, equivalently
      (call-with-values (lambda () EXP) (lambda (IDENTIFIER) BODY))

  (let-values ((FORMALS* EXP)) BODY) 
  ==> (call-with-values (lambda () EXP) (lambda FORMALS* BODY))

Some discussion:

dm == Dave Mason <dmason@xxxxxxxxxxxxxxx> 
lth == Lars Thomas Hansen <lth@xxxxxxxxxxx>

  dm> One thing it *could* buy is to simply use the existing names:
  dm> let, let*, letrec to handle multiple values too.  I don't have
  dm> an opinion as to whether this would be a good thing or not.

  lth> but it removes the ability to capture all returned values as a
  lth> list.

  dm> For this (I think) rare case,
  dm>   (let-values (((. I) E)) ...)
  dm> would seem to me to do the trick (although it might break some
  dm> readers).

Yeah, I wish this were possible with Scheme, but it really isn't.
Especially now that eval, sadly, is in the language.  Even those
readers that _don't_ break when given the datum (. X), I would presume
they would _read_ just X.  So in practice I'd say there's no way to
distinguish (. ID) from ID, even in those cases where an
implementation doesn't barf on (. ID).  

Note that if Scheme hadn't used the pun of improper lists == rest
args, and gone with a nice #rest keyword, we wouldn't be having this
problem.  But that's the subject for another SRFI, or something.

At any rate, I'd still vote for a let-values with a simpler semantics
that forces the programmer to use extra parens for the 'one-value'
case:

        (let-values ((x   1)) x) ==> (1)
        (let-values (((x) 1)) x) ==> 1

with the reasoning that 'let-values' really is different than 'let'.
Hence the different name.  

If a Scheme implementation folded the meanings of let and let-values
together, then the 'one-value special case' would be appropriate.  I'd
happily program in such a system.  

        (let ((x 1)
              ((y z) (values 2 3)))
          (list x y z))
        ==> (1 2 3)

even though I would lose the ability to bind rest-args

        (let ((x (values 2 3)))
          ...) 
        ==> error

Dylan is, in fact, such a system, but they got the #rest keyword
right, and so don't lose any power by merging the two forms.

-erik