Reputation: 13
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.
Upvotes: 0
Views: 143
Reputation: 48745
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
..
Upvotes: 2
Reputation: 13
So, I found a possible way to do it, I didn't though we could just ask a condition on the immediate value :
(define-syntax begin1
(syntax-rules ()
((begin1 body-expr-0 body-expr-1 body-expr-2 ...)
(if body-expr-1
(write body-expr-1)))))
Upvotes: -1