4

I've long since known that define is scary and should be used with caution unless you know for sure how your implementation handles it. Out of interest, I recently opened up R7RS and read all that I could find about define and nothing gave me the impression that any of it is implementation dependent. Have I missed something or is define no longer implementation-dependent in R7RS?

J. Mini
  • 1,868
  • 1
  • 9
  • 38
  • 1
    No, it's not implementation-dependent. I think early versions of Scheme made the shorthand format optional, but that hasn't been true for a long time. – Barmar Nov 16 '21 at 23:21
  • 1
    Implementations are allowed to add extensions anywhere in the language. So if Racket has added ways to use `define` that aren't specified in R7RS, that extension is implementation-dependent. But that's not specific to `define`. Racket also allows `[]` as alternatives for `()`, but that's not in R7RS, either. – Barmar Nov 16 '21 at 23:23
  • 1
    I've never heard anyone say that `define` is scary before. As long as you follow the appropriate RnRS spec it should work as advertised in any conforming implementation. Of course, different implementations may add some functionality. – ad absurdum Nov 16 '21 at 23:54

2 Answers2

3

You seem to be reading something into the answer you linked which isn’t there.

define has always been well defined, just as well-defined as let is. Most people choose to use define only at the top level of modules to create top-level bindings, but that’s a stylistic choice — it’s also capable of creating local bindings, like let is, if you use it inside and at the top of an ‘internal’ body, such as inside a procedure or a let or similar. Multiple defines in such a context are technically equivalent to letrec*, as another answer noted.

dpk
  • 200
  • 9
  • Yes, and I would summarize that at the lower level, `define` is a combination between the `bind` and the `set!` operators, usually created using the semantics of `letrec*` . – alinsoar Nov 24 '21 at 20:42
  • One minor point regarding the linked answer: How does `define` differ at the top level from being used internally? – J. Mini Apr 17 '22 at 12:40
  • @J.Mini At a library top level, a binding created by `define` can be exported for use by other libraries (in the R6RS, R7RS, and most implementation-specific library systems); an internal definition can only be seen within the block it is created. R5RS and R7RS also allow top-level defines to be intermixed with other, non-defining expressions, which is not allowed of internal definitions: expressions must follow all definitions. (R6RS also forbids arbitrarily mixing definitions and expressions at the top level.) – dpk Apr 17 '22 at 15:53
0

The most common interpretation of define is to replace it with letrec*.

But this problem has indeed many possible interpretations and the language does not impose any. Any interpretation is valid from the viewpoint of the language.

alinsoar
  • 15,386
  • 4
  • 57
  • 74
  • "The most common interpretation of define is to replace it with letrec*" — Isn't that for internal definitions only? From my understanding, in the outermost level of the program, `define` behaves much like `set!`. – Flux Nov 17 '21 at 12:47
  • @Flux Yes, internally, when you interpret it as `letlec*` it is also replaced by `set!`. This is what `letrec*` does. You can interpret it as `letrec*` everywhere and everything is ok. – alinsoar Nov 17 '21 at 12:48