As the Wikipedia article explains, begin
in Scheme is a library form that can be rewritten using more fundamental forms like lambda
.
But how do you rewrite a begin
, especially considering the following?
x
===> error: undefined identifier: x
(begin (define x 28) x)
===> 28
x
===> 28
Scheme begin expressions aren't just code blocks, though, because they are expressions that return a value. A begin returns the value of the last expression in the sequence. For example, the begin expression above returns the value returned by the call to bar . The bodies of procedures work like begin s as well.
A Scheme expression is a construct that returns a value, such as a variable reference, literal, procedure call, or conditional. Expression types are categorized as primitive or derived. Primitive expression types include variables and procedure calls.
Just define the value at the toplevel like a regular variable and then don't change it. To help you remember, you can adopt a convention for naming these kinds of constants - I've seen books where toplevel variables are defined with *stars* around their name.
In Scheme, you can use local variables pretty much the way you do in most languages. When you enter a let expression, the let variables will be bound and initialized with values. When you exit the let expression, those bindings will disappear.
You cannot. The thing is that begin
has two roles: one is sequence a bunch of side-effectful expressions, and the other is that it is used to "splice" macro results. The fact that you can use begin
with a definition as in the above is a result of this second feature, and you cannot write it yourself.
If you really want to follow the whole story, then you could define begin
as the simple macro which makes it do only the sequencing aspect (and it can indeed be implemented as such, though usually it isn't). But, you need to add explicit recognition of begin
s to splice definitions (toplevel or internal). This means that a macro implementation is fine, but it cannot really be a library because the core expander should know about it. (And because the language is lexically scoped, there is no good way for the core expander to identify begin
s that are not defined in the core language.)
To summarize all of this, you could say that R5RS is only wrong in classifying begin
as "library syntax", since it can't be defined in a library... but even that's not entirely accurate since R5RS defines "library syntax" as just "derived expressions". The real wrong point is, therefore, the fact that one of begin
s two faces is implemented elsewhere, in the expander (for definition contexts).
Note also that R6RS clarifies the whole deal: the two faces of begin
are made explicit, and it is now part of the core language, not a "library form", and not even a derived form.
You are still welcome to try writing a version of begin which satisfies its first role: sequencing.
(define-syntax sequencing
(syntax-rules ()
[(_ expression) expression]
[(_ expression expressions ...)
((lambda (ignored) (sequencing expressions ...)) expression)]))
Here is the post from which I took that snippet. It provides better context if you are interested, and you might be.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With