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.
Whenever I use let-values, I always write it as (let-values ((Formals Exp) ...) Exp ... Exp) rather than this SRFI's (let-values (Formals Exp) Exp ... Exp) I do understand that the extra parens are annoying when there's only one binding, which is why I frequently use one of two other forms when I only care to use one binding. When I'm thinking about monads I tend to use (bind (Formals Exp) Exp ... Exp) which works just as this SRFI's version. In most of my usual coding I use (with-values Exp Consumer) ; Consumer should evaluate to a procedure because (a) I'm pretty used to cps, (b) it's an extremely short macro, and (c) it only uses a trifle (two spaces) more horizontal space than bind. So I suppose you should count me in as another vote for making let-values look more like let, and perhaps supplying let*-values and letrec-values as well (though letrec-values is hard to write portably -- see below for my all-too-cryptic version). However, I'm _definitely_ against the special one-return-value case that Michael Sperber suggests, for all the reasons already stated. And while I agree that the one-decl let-values and the multi-decl let-values are syntactically distinguishable, I don't like that as an argument for choosing one over the other. Whatever this SRFI decides will have a certain weight. I view the fact that an implementation can provide an extended syntax as a bug, not a feature: I don't want to explain to students or co-workers that 'it works both ways' in implementation X. -erik (define-syntax bind (syntax-rules () ((bind (Formals Exp) Body0 Body ...) (call-with-values (lambda () Exp) (lambda Formals Body0 Body ...))))) (define-syntax with-values (syntax-rules () ((with-values Exp Consumer) (call-with-values (lambda () Exp) Consumer)))) (define-syntax let-values (syntax-rules () ((let-values () Body0 Body ...) (let () Body0 Body ...)) ((let-values ((Formals Exp) Decl ...) Body0 Body ...) (let ((temp (lambda () Exp))) (let-values (Decl ...) (call-with-values temp (lambda Formals Body0 Body ...))))))) (define-syntax let*-values (syntax-rules () ((let*-values () Body0 Body ...) (let () Body0 Body ...)) ((let*-values ((Formals Exp) Decl ...) Body0 Body ...) (call-with-values (lambda () Exp) (lambda Formals (let*-values (Decl ...) Body0 Body ...)))))) ;;; This one's pretty convoluted. Don't try this at home, kids. ;;; The general idea for this macro is to spend some cycles ;;; accumulating all of the variables in the formals, and associating ;;; with each one a temporary variable (generated magically through ;;; hygiene). This trick is also used in the letrec macro in R5RS. ;;; Here, as there, we use string cookies to simulate helper macros. ;;; letrec-values is more complicated because we need an inner and an ;;; outer accumulator. The outer accumulator iterates over the decls, ;;; each time gathering a new list of pairs of FormalVariable x Temp. ;;; That list is consed onto the list of all such pairs, and saved ;;; with the Formals and Exp of the decl. The inner accumulator ;;; iterates over the formal parameter lists/symbols/improper-lists ;;; themselves. (define-syntax letrec-values (syntax-rules () ((letrec-values ((Formals Exp) ...) Body0 Body ...) (letrec-values "OUTER" ((Formals Exp) ...) () () (begin Body0 Body ...))) ((letrec-values "OUTER" ((Formals Exp) Decl ...) TempsOut DeclsOut Body) ;; we need to process a new formals list. (letrec-values "INNER" Formals () Formals Exp (Decl ...) TempsOut DeclsOut Body)) ((letrec-values "OUTER" () ((Var Temp) ...) ((Formals Exp ((DeclVar DeclTemp) ...)) ...) Body) ;; we're done processing all the decls. Time to expand. (let ((Temp #f) ...) (call-with-values (lambda () Exp) (lambda Formals (set! DeclTemp DeclVar) ... #f)) ... (let ((Var Temp) ...) Body))) ((letrec-values "INNER" (Var . Rest) InnerTempsOut Formals Exp Decls TempsOut DeclsOut Body) ;; we found a new variable, so generate a temp and go on. (letrec-values "INNER" Rest ((Var temp) . InnerTempsOut) Formals Exp Decls ((Var temp) . TempsOut) DeclsOut Body)) ((letrec-values "INNER" () InnerTempsOut Formals Exp Decls TempsOut DeclsOut Body) ;; we're done with these formals. Go back to the outer loop. (letrec-values "OUTER" Decls TempsOut ((Formals Exp InnerTempsOut) . DeclsOut) Body)) ((letrec-values "INNER" Var InnerTempsOut Formals Exp Decls TempsOut DeclsOut Body) ;; we've found a rest variable. Go back to the outer loop. (letrec-values "OUTER" Decls ((Var temp) . TempsOut) ((Formals Exp ((Var temp) . InnerTempsOut)) . DeclsOut) Body))))