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 <greghendersh...@gmail.com>
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 <lojicdot...@gmail.com> 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
>> <matt...@felleisen.org> wrote:
>> >
>> >
>> >
>> > > On Mar 11, 2019, at 11:21 AM, Brian Adkins <lojic...@gmail.com>
>> 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 racket-users...@googlegroups.com.
>> > 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 racket-users+unsubscr...@googlegroups.com.
> 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 racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to