Гигиенический макрос r7rs: вернуть значение второго выражения
В настоящее время я изучаю некоторые r7rs и пытаюсь реализовать макрос 'begin' следующим образом:
(begin0 expr0 expr1 ... expr2)
С expr, являющимся регулярным выражением (Like (set! X (+ x 1)))
И begin0 как макрос, который вычисляет все выражения, но возвращает только результат expr1.
Например:
(let ((year 2017))
(begin1 (set! year (+ year 1))
year
(set! year (+ year 1))
year))
Это должно вернуть 2018
Сначала я создал функцию начала:
(define-syntax begin0
(syntax-rules ()
((begin-0 body-expr-0 body-expr-1 ...)
(let ((tmp body-expr-0)) body-expr-1 ... tmp))))
И теперь я пытаюсь понять, как я могу сделать, чтобы вернуть значение "body-expr-1"? Я сделал следующий код, но он говорит, что мне не хватает многоточия, и я не понимаю, как это сделать.
(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))))))
Я надеюсь, что это достаточно понятно, спасибо за ответы.
2 ответа
Это может быть сделано, но макрос будет мешать так, что вы не можете делать все с begin1
как с begin
,
(define-syntax begin1
(syntax-rules ()
((_ expr0 expr1 exprn ...)
(begin
expr0
(let ((result expr1))
exprn ...
result)))))
Код, который не работает, это:
(begin1
(define global1 10)
test3
(define global2 20))
Причина очевидна. Расширяется до:
(begin1
(define global1 10)
(let ((result~1 test3))
(define global2 20)
result~1))
Второй define
будет изменен на letrec
такой, что переменная global2
доступно только на время let
, У меня нет решения для этого, так как это требует от вас, чтобы иметь возможность делать глобальные define
от закрытия.
begin1
довольно странная особенность. В Ракетке и, возможно, на других диалектах Схемы мы имеем begin0
который возвращает результат первого выражения. Это очень полезно. например. вот счетчик:
(define (get-counter from)
(lambda ()
(let ((tmp from))
(set! from (+ from 1))
tmp)))
И с begin0
:
(define (get-counter from)
(lambda ()
(begin0
from
(set! from (+ from 1)))))
В ракетке begin0
это примитив. Так что это форма, поддерживаемая в полностью расширенной программе и, таким образом, реализованная в C, так же, как begin
..
Итак, я нашел возможный способ сделать это, но не смог, хотя мы могли бы просто спросить условие о немедленном значении:
(define-syntax begin1
(syntax-rules ()
((begin1 body-expr-0 body-expr-1 body-expr-2 ...)
(if body-expr-1
(write body-expr-1)))))