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.

Reply via email to