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

Re: Making the new let easier to stomach



sperber@xxxxxxxxxxxxxxxxxxxxxxxxxxx (Michael Sperber [Mr. Preprocessor]) writes:
> - You're essentially arguing for replacing R5RS let with the one you propose.
>   This is totally valid.
> 
>   As it SRFI, your proposal is still only a suggestion for an addition to the
>   language.  Why not rename it to something other than let?

I proposed SRFI-5 specifically to patch two little holes that I perceived in
the R5RS let form, inconsistencies with respect to other R5RS features.  I like
to think that these little holes are oversights that would have been corrected
at the time the named-let and signature-style define features were introduced,
had they been noticed.  Providing the functionality of SRFI-5's let form under
a different name would defeat much of the reason why it was submitted.

>   This would also make it easier to use for people dealing with legacy code.

SRFI-5 is backward-compatible with R5RS's let and uses only one syntactic
extension (symbols in the binding list) to implement its two new facets.  How
serious can a legacy problem be?

> - Is there a way to define the construct using standard R5RS macros rather
>   than explicit renaming (which is only supported by one or two Scheme
>   systems)?

Heh heh, R5RS template-style macros?  See bottom.  I wouldn't be surprised if
a template wizard were able to optimize it a bit, so I'd appreciate it if
someone gave it a sound thrashing.  Not heavily tested, but it appears to work.

Regards, [Ag]   Andy Gaynor   silver@xxxxxxxxxxxxxxxx
_______________________________________________________________________________

(define-syntax let
  (syntax-rules ()

    ;; In the (let 0 name normals rest arguments body bindings) form:
    ;;     name:      The name to assign to the lambda, or #f if none.
    ;;     normals:   The normal parameters of the lambda.
    ;;     rest:      The rest parameter for the lambda, or () if none.
    ;;                Using () saves a rule for (normal ... . rest).
    ;;     arguments: The arguments to the lambda.
    ;;     body:      The body of the lambda.
    ;;     bindings:  Bindings remaining to be processed.

    ;; Terminating cases
    ;; No name, use an anonymous lambda call
    ((let 0 #f (normal ...) rest arguments body ())
     ((lambda (normal ... . rest) . body) . arguments))
    ;; Name, use a letrec and call
    ((let 0 name (normal ...) rest arguments body ())
     (letrec ((name (lambda (normal ... . rest) . body))) (name . arguments)))

    ;; Deconstructing bindings
    ;; Shuffle a normal binding
    ((let 0 name (normal ...) () (argument ...) body ((variable value) . bindings))
     (let 0 name (normal ... variable) () (argument ... value) body bindings))
    ;; Shuffle a rest binding (its values are shuffled below)
    ((let 0 name normals () arguments body (rest-variable . rest-values))
     (let 0 name normals rest-variable arguments body rest-values))
    ;; Shuffle a rest value
    ((let 0 name normals rest (argument ...) body (rest-value . rest-values))
     (let 0 name normals rest (argument ... rest-value) body rest-values))

    ;; Top-level interface
    ;; Straight let, no bindings
    ((let () . body)
     (let 0 #f () () () body ()))
    ;; Straight let, bindings
    ((let ((variable value) . bindings) . body)
     (let 0 #f (variable) () (value) body bindings))
    ;; Signature-style named let
    ((let (name . bindings) . body)
     (let 0 name () () () body bindings))
    ;; Non-signature-style named let
    ((let name bindings . body)
     (let 0 name () () () body bindings))))