Мой макрос lisp перестает работать в последней версии

У меня есть макрос, который я написал в 2010 году, он был для управления структурами, как в Common Lips, с использованием Alists (здесь весь файл, включая функции https://jcubic.pl/struct.txt).

(define-macro (defstruct name . fields)
  "Macro implementing structures in guile based on assoc list."
  (let ((names (map (lambda (symbol) (gensym)) fields))
        (struct (gensym))
        (field-arg (gensym)))
    `(if (not (every-unique ',fields))
        (error 'defstruct "Fields must be unique")
        (begin
          (define (,(make-name name) ,@names)
        (map cons ',fields (list ,@names)))
          ,@(map (lambda (field)
               `(define (,(make-getter name field) ,struct)
              (cdr (assq ',field ,struct)))) fields)
          ,@(map (lambda (field)
               `(define (,(make-setter name field) ,struct ,field-arg)
              (assq-set! ,struct ',field ,field-arg)
              ,field-arg)) fields)
          (define (,(make-predicate name) ,struct)
        (and (struct? ,struct)
             (let ((result #t))
               (for-each (lambda (x y)
                   (if (not (eq? x y)) (set! result #f)))
                 ',fields
                 (map car ,struct))
               result)))))))

Работало нормально. Я недавно обновил этот макрос для моих губ в JavaScript (он основан на схеме), и когда я его вызывал, он возвращался false и хотел знать, так ли это будет работать в коварстве. Но оказывается, что это не работает в коварстве вообще. Это показывает эту ошибку:

При компиляции выражения: ОШИБКА: синтаксическая ошибка: неизвестное расположение: определение в контексте выражения, где определения недопустимы, в форме (define (make-point #{ g746}# #{ g747}#) (map cons (quote (x y)) (список #{ g746}# #{ g747}#))

Почему у меня есть эта ошибка и как ее исправить, чтобы она снова работала в guile? Я был давно, я не помню, как я тестировал этот код, но открытие guile с помощью функции load или копирование, вставка кода в интерпретатор - все выдает ту же ошибку.

Я использую guile 2.0.14 на GNU / Linux.

PS: я предпочитаю использовать макросы lisp ИМО, они превосходят странные схемы гигиенических макросов.

1 ответ

Решение

Похоже, что современная схема guile не видит начала в if в качестве допустимой опции для запуска нового определения контекста. Возможно, это ошибка или лучшее выравнивание схемы дону. Но в следующем примере кода показан метод исправления вашего кода для более поздней версии guile (вам может понадобиться создать define-values, так как это более свежее дополнение к guile. PS использование макросов lisps в guile - это обман, и вы попадете в Беда, если вы планируете много спланировать, макросы похожи на парены, если вы привыкнете, они будут выглядеть естественно.

Вот код,

(define-macro (defstruct name . fields)
   "Macro implementing structures in guile based on assoc list."
   (let* ((names (map (lambda (symbol) (gensym)) fields))
          (struct    (gensym))
          (field-arg (gensym))
          (sname     (make-name name))
          (predname  (make-predicate name))
          (getnames  (map (lambda (f) (make-getter name f)) fields))
          (setnames  (map (lambda (f) (make-setter name f)) fields)))

      `(define-values (,sname ,predname ,@getnames ,@setnames)
         (if (not (every-unique ',fields))
             (error 'defstruct "Fields must be unique")
             (let ()
               (define (,sname ,@names)
                 (map cons ',fields (list ,@names)))
               ,@(map (lambda (field)
                  `(define (,(make-getter name field) ,struct)
                      (cdr (assq ',field ,struct)))) fields)
               ,@(map (lambda (field)
                  `(define (,(make-setter name field) ,struct ,field-arg)
                      (assq-set! ,struct ',field ,field-arg)
                  ,field-arg)) fields)
               (define (,predname ,struct)
                  (and (struct? ,struct)
                       (let ((result #t))
                          (for-each (lambda (x y)
                             (if (not (eq? x y)) (set! result #f)))
                           ',fields
                          (map car ,struct))
                          result)))

                 (values ,sname ,predname ,@getnames ,@setnames))))))

Вот версия define-values (посмотрите на код после #' чтобы увидеть, что он делает)

(define-syntax define-values
   (lambda (x)
      (syntax-case x ()
        ((_ (f ...) code ...)
         (with-syntax (((ff ...) (generate-temporaries #'(f ...))))
           #'(begin
               (define f #f)
                ...
               (call-with-values (lambda () code ...)
                  (lambda (ff ...)
                     (set! f ff)
                     ...))))))))
Другие вопросы по тегам