Схема Chez: импорт макросов на верхнем уровне - PullRequest
0 голосов
/ 14 января 2019

Я использую Chez Scheme 9.5 и пытаюсь определить синтаксический преобразователь в библиотека. Вот пример:

(library (forlib)
  (export for)
  (import (rnrs (6)))

  (define-syntax for
    (syntax-rules (in)
      [(for x in lst body1 body2 ...)
       (for-each (lambda (x) body1 body2 ...) lst)])))

Я сохраняю это в файле forlib.ss и запускаю chez из того же каталога. Тогда в REPL я получаю это:

> (import (forlib))
> (for x in '(1 2 3) (display x))
Exception: invalid syntax (for x in (quote (1 2 3)) (display x))
Type (debug) to enter the debugger.

Если я изменю определение синтаксиса на

(define-syntax for
  (syntax-rules ()
    [(for x lst body1 body2 ...)
     (for-each (lambda (x) body1 body2 ...) lst)])))

(без ключевого слова in), все работает:

> (import (forlib))
> (for x '(1 2 3) (display x))
123
> _

Вернуться к старому определению с ключевым словом in. Если я помещу тестовый код в тестовый файл:

;;; test-for.ss
(import (rnrs (6))
        (forlib))

(for x in '(1 2 3) (display x))

и попробуйте выполнить этот файл, результат зависит от того, как я выполняю файл. Если я запускаю эту программу, используя chez --program, она работает как положено:

$ chez --program test-for.ss
123
$ _

Если я запускаю его, используя chez --script, я получаю ту же ошибку, что и выше:

$ chez --script test-for.ss
Exception: invalid syntax (for x in (quote (1 2 3)) (display x)) at line 6, char 1 of test-for.ss
$ _

Это поднимает два вопроса:

  • Почему REPL и --script хороши с импортом синтаксических форм без специальные ключевые слова, но отказывается принимать синтаксические формы, которые имеют специальные ключевые слова в них?
  • В чем именно разница между --script и --program? руководство пользователя говорит, что --program означает, что содержимое файла интерпретируется как программа верхнего уровня rnrs, но ничего не говорит о том, что семантика --script являются.

Наконец, чтобы завершить мою запутанность, введя приведенное выше определение синтаксиса прямо в REPL, тогда все работает как положено:

> (define-syntax for
    (syntax-rules (in)
      [(for x in lst body1 body2 ...)
       (for-each (lambda (x) body1 body2 ...) lst)])))
> (for x in '(1 2 3) (display x))
123
> _

Так что же отличается в REPL между синтаксическими преобразователями, импортированными из библиотека и синтаксические преобразователи, определенные непосредственно в REPL?

1 Ответ

0 голосов
/ 15 января 2019

В схеме Chez некоторые семантики отличаются между режимами работы. Я собираюсь назвать эти режимы r6rs и repl.

R6RS:

  • программ (--program в командной строке)
  • Библиотека

РЕПЛ:

  • скрипты (--script в командной строке)
  • файлы (с использованием процедуры загрузки или в качестве аргументов интерфейса командной строки без --program или --script)
  • и ответ, конечно же

Для вашего конкретного вопроса вам нужно определить и экспортировать идентификатор с именем in из forlib, если вы хотите, чтобы repl и сценарии соответствовали поведению библиотек и программ. Это может быть так же просто, как пустое определение, или вы можете сделать синтаксическое определение, которое выдает ошибку при использовании вне тела макроса. Простой:

(library (forlib)
  (export for in)
  (import (rnrs))

  (define in)

  (define-syntax for ...)
)

Синтаксическое определение:

(library (forlib)
  (export for in)
  (import (rnrs))

  (define-syntax in
    (identifier-syntax
      (error #f "Misplaced aux syntax in")))

  (define-syntax for ...)
)

Оба работают нормально; используйте то, что вы предпочитаете.

Другие различия между режимами repl и r6rs, о которых я знаю, проистекают из того, как они оценивают выражения. В режиме repl каждое выражение обрабатывается самостоятельно. То есть Chez читает выражение, оценивает его и, возможно, печатает результаты. В режиме r6rs все содержимое файла оценивается как единое целое. В явном виде, продолжением верхнего уровня режима repl является «read, eval, возможно print и loop», а продолжением верхнего уровня режима r6rs является следующее выражение. Например, этот код будет вести себя по-разному при запуске в качестве программы или скрипта:

(import (chezscheme))

(define println)

(printf "~x\n"
  (call/cc (lambda (k)
             (set! println k)
             1)))

(println 5)
(println 6)

Другое отличие состоит в том, что в режиме r6rs вы не можете определить функцию, а затем использовать ее в макросе с синтаксическим регистром вне синтаксической кавычки.

(define ($two) 2)

(define-syntax two
  (lambda (x)
    (syntax-case x ()
      [_ ($two)])))
...