Eli Barzilay wrote at 06/03/2012 11:25 PM:
The way I see it, there are several problems with internal `define's
as they currently stand, in decreasing order of importance:

1. Easy to make hard-to-find bugs in both code refactoring and in new
    code.

I think that a lot of these problems would be avoided if in most cases we could get rid of toplevel-like magic for internal bindings, and also have the internal "define" form have syntactic terms to make its scope explicit (and control flow can just proceed into "SCOPE-BODY" from the context in which the "define/scope" appears):

(define/scope ID VAL-EXPR SCOPE-BODY ...+)

Since each such binding form in a series, even when such bindings don't depend on each other, would increase rightward drift, since they'd have to be nested, the form should accommodate multiple simultaneous bindings (simultaneous wrt both "VAL-EXPR"s and bindings):

(define/scope ((ID VAL-EXPR) ...+) SCOPE-BODY ...+)

For non-simultaneous bindings, in which a "VAL-EXPR" can refer to a previously-encountered "ID", we can avoid the rightward drift of nesting by introducing an additional form:

(define/scope/sequenced ((ID VAL-EXPR) ...+) SCOPE-BODY ...+)

For the occasions on which we want to bind mutually-recursive internal procedures simultaneously, with some magic approaching that of toplevel, we should warn of that fact with an identifier we don't like to type as much:

(define/scope/here-there-be-dragons ((ID VAL-EXPR) ...+) SCOPE-BODY ...+)

For recursive algorithms, someone suggested that it would be very convenient if "SCOPE-BODY" could treat the binding context as a procedure, providing different values for the "ID"s, so we get an additional form:

(define/scope/proc PROC-ID ((ID VAL-INIT) ...+) SCOPE-BODY ...+)

Now we just need shorter names for these different forms.

2. Lack of ability to mimic the `let*'-with-repeated-name idiom.

3. Reduces the "verbosity" when measured in nestings, but tends to add
    more text overall; in addition, the indentation of the named
    expression is usually the same because `define' is so long; and in
    addition, it's common to type many definitions, and as much as I
    use a sophisticated editor I end up typing it verbatim a lot.

The internal "define" verbosity increases more in syntax transformer templates.

Where the gaps are substantial (that is, #1 is much more important IMO
than #2, which is much more important than #3).

Such a `def+' (which is subtly different from the previously mentioned
`define*') is something that I'm not sure that the definition-context-
police will let through, but having #2 seems still important enough
that I worry that it won't become popular and therefore the #1 point
is still pending.

I can see why some people want to have internal "define": it looks friendlier, you can toss in a binding in many places without having to think too much about scope or nest your parens, and you don't have to tell newbies that they need different syntax for internal bindings (even though the semantics might be more different than they assume).

I'm also wary of the pitfall of inflexibly clinging to the familiar. I've been using "let" in Scheme descendants for a decade, and in other Lisp descendants for a decade before that, so I'm very comfortable with "let"*. The relative advantages of "define" would have to be big for me to choose to give up the relative advantages of "let"* to which I've become accustomed. I don't actually know how you'd improve "define" to make it more compelling to me.

I asked about multiple-value "let"*. All I wanted was to renovate my kitchen, but instead you're trying to sell me a downtown penthouse. You're going to have to sell me on why I'd want the downtown lifestyle, and allay my concerns about social diseases. We could just renovate my kitchen *while* you refine the downtown living story.

Neil V.

____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to