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?

- 1,868
- 1
- 9
- 38
-
1No, 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
-
1Implementations 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
-
1I'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 Answers
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 define
s in such a context are technically equivalent to letrec*
, as another answer noted.

- 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
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.

- 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