I think it's fair to say that the Racket style guide is not as rigid as some other style guides for some other languages: as it says itself in the introduction, it "isn’t complete and it isn’t perfect" and is more a set of "guidelines and best practices" than binding universal rules. I think it is usually right (even about some things I didn't agree with the first time I read it), but I have a number of personal quirks in my style, as do many others whose code I've read. (For example, I think several of us experiment with brackets or braces instead of parentheses to distinguish `define-values` left-hand-sides from the form of `define` with a function header.)
In terms of `define` specifically, I think using `let` or `let*` instead when that is your intended semantics is justifiable under the style guide, and I sometimes do so myself. Even the guide itself <https://docs.racket-lang.org/style/Choosing_the_Right_Construct.html#%28part._.Definitions%29> gives a `let*` that "is not easily replaced with a series of defines." The example it calls out as "bad" uses `let` for a single, simple local definition, which I think is a much more clear-cut case of rightward drift with no corresponding benefit.\ On Mon, Mar 11, 2019 at 1:17 PM Greg Hendershott <[email protected]> wrote: > As a new user, it's possible to have the intuition that `define` is > just a way to avoid indentation -- that it "writes a `let` for you, > from the point of the define to 'the end of the enclosing scope'". That would be a reasonable intuition and arguably a nice semantics. I'm curious about what new users actually do think—I expect it depends on what language they come from. Off hand, I think `letrec` semantics is fairly common for local definitions, and I think a lot of mainstream languages don't make `let` or `let*` semantics available at all. (For a particularly egregious example, in Python, IIUC, it isn't always possible to even determine whether an identifier is bound or not until runtime.) -Philip On Mon, Mar 11, 2019 at 1:23 PM Brian Adkins <[email protected]> wrote: > Yes, I hadn't really thought through the semantics of define (i.e. whether > it had let or letrec semantics). So, in my case, since I want let > semantics, I will use let. I'm happy to follow the Racket style guide when > I get to the point of contributing code that is covered by it, but I think > I will use let, when I want let semantics, for my own code. > > On Monday, March 11, 2019 at 1:17:47 PM UTC-4, Greg Hendershott wrote: >> >> To be fair: >> >> As a new user, it's possible to have the intuition that `define` is >> just a way to avoid indentation -- that it "writes a `let` for you, >> from the point of the define to 'the end of the enclosing scope'". >> >> And it's possible for that intuition to seem correct for a very long >> time -- until you hit an example like Brian did. And then you need to >> learn about `letrec`. >> >> (As a non-new user, 99.9% of the time that I use a local `define` I >> actually wish it were "like `let`" not `letrec`, but I use it anyway >> and try to be careful.) >> >> >> On Mon, Mar 11, 2019 at 12:29 PM Matthias Felleisen >> <[email protected]> wrote: >> > >> > >> > >> > > On Mar 11, 2019, at 11:21 AM, Brian Adkins <[email protected]> >> wrote: >> > > >> > > I just discovered that define will fail at runtime, where let would >> fail at compile time. Besides helping to keep the indentation level from >> marching to the right "too much", what are the benefits of define over let? >> > > >> > > --- snip --- >> > > #lang racket >> > > >> > > (define (f n) (+ n 1)) >> > > >> > > (define (foo) >> > > (define b (f a)) >> > > (define a 7) >> > > >> > > b) >> > > >> > > (define (bar) >> > > (let ([b (f a)] >> > > [a 7]) >> > > >> > > b)) >> > > --- snip --- >> > >> > >> > >> > I think your characterization is a bit misleading here. >> > >> > In ‘bar’ ‘a’ is not bound, something that Racket (and DrRacket) >> properly signal at compile time. >> > >> > In ‘foo’ ‘a’ *is* bound, because you’ve set up a mutually recursive >> scope. But, when Racket evaluates (foo) it notices that ‘a’ is bound but >> uninitialized, which is two different things. >> > >> > If you want to compare apples to apples, use a ‘letrec' instead of a >> ‘let' in ‘bar'. Then you have (1) the same semantics and (2) the same >> error. >> > >> > — Matthias >> > >> > -- >> > You received this message because you are subscribed to the Google >> Groups "Racket Users" group. >> > To unsubscribe from this group and stop receiving emails from it, send >> an email to [email protected]. >> > For more options, visit https://groups.google.com/d/optout. >> > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.

