I'm currently learning some r7rs and I am trying to implement a macro 'begin' as following :
(begin0 expr0 expr1 ... expr2)
With expr being a regular expression (Like (set! x (+ x 1)))
And begin0 as a macro that evaluates all the expression but return only the expr1 result.
For example :
(let ((year 2017))
(begin1 (set! year (+ year 1))
year
(set! year (+ year 1))
year))
It musts return 2018
I've created a begin function first :
(define-syntax begin0
(syntax-rules ()
((begin-0 body-expr-0 body-expr-1 ...)
(let ((tmp body-expr-0)) body-expr-1 ... tmp))))
And now, I'm trying to understand how I can do to return the value of "body-expr-1" ? I've done the following code, but it says that I'm missing some ellipsis and I don't understand how to do it.
(define-syntax begin1
(syntax-rules ()
((begin1 body-expr-0 body-expr-1 ... body-expr-2)
(let ((tmp body-expr-0) body-expr-1 ... tmp)
(cond (eq? tmp body-expr-1)
(begin . tmp))))))
I hope that it is understandable enough, thanks for the answers.
This can be done, but the macro will interfere such that you cannot do all the things with begin1
as with begin
.
(define-syntax begin1
(syntax-rules ()
((_ expr0 expr1 exprn ...)
(begin
expr0
(let ((result expr1))
exprn ...
result)))))
The code that does not work is this:
(begin1
(define global1 10)
test3
(define global2 20))
The reason is obvious. It expands to:
(begin1
(define global1 10)
(let ((result~1 test3))
(define global2 20)
result~1))
The second define
will be changed to a letrec
such that the variable global2
is only available for the duration of the let
. I have no fix for this since it requires you to be able to do global define
from a closure.
begin1
is rather strange feature. In Racket and perhaps other Scheme dialects we have begin0
that returns the result of the first expression. This is very useful. eg. here is a counter:
(define (get-counter from)
(lambda ()
(let ((tmp from))
(set! from (+ from 1))
tmp)))
And with begin0
:
(define (get-counter from)
(lambda ()
(begin0
from
(set! from (+ from 1)))))
In Racket begin0
is a primitive. So it is a form supported in the fully expanded program and thus implemented in C, just like begin
..