Гигиенический макрос r7rs: вернуть значение второго выражения - PullRequest
0 голосов
/ 27 ноября 2018

В настоящее время я изучаю некоторые 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 ]

0 голосов
/ 28 ноября 2018

Это можно сделать, но макрос будет мешать так, что вы не можете делать все с помощью 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 довольно странная особенность.В Racket и, возможно, на других диалектах Scheme у нас есть 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 ..

0 голосов
/ 27 ноября 2018

Итак, я нашел возможный способ сделать это, но я не нашел, хотя мы могли бы просто задать условие для немедленного значения:

(define-syntax begin1
  (syntax-rules ()
    ((begin1 body-expr-0 body-expr-1 body-expr-2 ...)
       (if body-expr-1
          (write body-expr-1)))))
...